Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/162.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 不同类型的专门化_C++_Templates_C++11_Specialization - Fatal编程技术网

C++ 不同类型的专门化

C++ 不同类型的专门化,c++,templates,c++11,specialization,C++,Templates,C++11,Specialization,有人能告诉我如何删除下面重复的专业吗 #include <iostream> #include <fstream> #include <string> struct Thing { int a, b; void load (std::istream& is) {is >> std::skipws >> a >> b;} }; struct Object { int a, b, c;

有人能告诉我如何删除下面重复的专业吗

#include <iostream>
#include <fstream>
#include <string>

struct Thing {
    int a, b;
    void load (std::istream& is) {is >> std::skipws >> a >> b;}
};

struct Object {
    int a, b, c;
    void load (std::istream& is) {is >> std::skipws >> a >> b >> c;}
};

template <typename...> struct PassArgs;

// General case.
template <typename First, typename... Rest>
struct PassArgs<First, Rest...> : PassArgs<Rest...> {
    void operator()(std::istream& is, First& first, Rest&... rest) const {
        is >> first;
        PassArgs<Rest...>::operator()(is, rest...);
    }
};

// Specialization for std::string needed.
template <typename... Rest>
struct PassArgs<std::string, Rest...> : PassArgs<Rest...> {
    void operator()(std::istream& is, std::string& first, Rest&... rest) const {
        while (std::getline (is, first) && first.empty());
        PassArgs<Rest...>::operator()(is, rest...);
    }
};

// Specialization for class Thing.
template <typename... Rest>
struct PassArgs<Thing, Rest...> : PassArgs<Rest...> {
    void operator()(std::istream& is, Thing& first, Rest&... rest) const {
        first.load(is);
        PassArgs<Rest...>::operator()(is, rest...);
    }
};

// Specialization for class Object, but is the exact same as that for Thing.
template <typename... Rest>
struct PassArgs<Object, Rest...> : PassArgs<Rest...> {
    void operator()(std::istream& is, Object& first, Rest&... rest) const {
        first.load(is);
        PassArgs<Rest...>::operator()(is, rest...);
    }
};


template <>
struct PassArgs<> {
    void operator()(std::istream&) const {}  // End of recursion.
};


int main() {}

大约有无数种方法可以做到这一点。这里有一个

首先,检测是否有要调用的成员
load()
的特征。这里有一种写的方法:

namespace details {    
    template<class T>
    auto has_load_impl(int) 
         -> decltype((void)std::declval<T&>().load(std::declval<std::istream&>()),
                     std::true_type());

    template<class T>
    std::false_type has_load_impl(...);

    template<class T>
    using has_load = decltype(has_load_impl<T>(0));
}
如果您在其他地方不需要独立特性,也可以不使用独立特性,直接在
do\u load
函数中输入:

namespace details {
    template<class T>
    auto do_load(std::istream& is, T& t, int) -> decltype((void)t.load(is)){
        t.load(is);
    }

    template<class T>
    void do_load(std::istream& is, T& t, ...){
        is >> t;
    }
}

template<class T>
void load(std::istream& is, T& t){
    details::do_load(is, t, 0);
}
最后,
PassArgs
本身可以简化为两行函数,使用熟悉的在带括号的init列表中进行包扩展的技巧:


定义一个特征来检测
加载
成员:

template<typename T> using void_t = void;

template<typename T, typename = void_t<>>
  struct has_load
  : std::false_type { };

template<typename T>
  struct has_load<T, void_t<decltype(std::declval<T&>().load(std::declval<std::istream&>()))>>
  : std::true_type
  { };
然后在主模板中使用它:

// General case.
template <typename First, typename... Rest>
  struct PassArgs : PassArgs<Rest...> {
    void operator()(std::istream& is, First& first, Rest&... rest) const
    {
        PassArg<First>::pass(is, first);
        PassArgs<Rest...>::operator()(is, rest...);
    }
};
注意:我让新类有一个名为
pass
的静态函数,而不是
operator()
,因为如果您发现自己在写这个:

PassArgs<Args...>()(is, args...);
那么你可能不想要函子
PassArgs
是无状态的,因此没有必要创建它的实例,如果您必须显式地命名
operator()
,那么您就错了。为函数指定一个适当的名称并调用该名称,并使其为静态:

PassArgs<Rest...>::sensible_name(is, rest...);
PassArgs::sensible_name(is,rest…);

我将一直使用ADL解决方案

首先,这里是基于
friend
的负载支持

struct Thing {
  int a, b;
  friend void load (std::istream& is, Thing& t) {is >> std::skipws >> t.a >> t.b;}
};
基于构件的荷载:

struct Object {
  int a, b, c;
  void load (std::istream& is) {is >> std::skipws >> a >> b >> c;}
};
首先,一些元编程样板。不使用样板文件,您可以在更少的行中执行此操作,但它会使它更干净:

namespace meta {
  namespace details {
    template<template<class...>class Z, class=void, class...Ts>
    struct can_apply : std::false_type {};
    template<template<class...>class Z, class...Ts>
    struct can_apply<Z, decltype((void)(std::declval<Z<Ts...>>())), Ts...>:
      std::true_type
    {};
  }
  template<template<class...>class Z, class...Ts>
  using can_apply = details::can_apply<Z,void,Ts...>;
}
template<class T>
using member_load = decltype( std::declval<T>().load(std::declval<std::istream&>()) );

template<class T>
using stream_load = decltype( std::declval<std::istream&>() >> std::declval<T>() );
我们现在可以调用
load::load\u many(is,a,b,c,d)

std::string
有一个自定义的
load::load
函数,以及您想要支持的
std
中的任何其他特定类型。例如,您可以在
命名空间加载
中编写
模板void load(std::istream&is,std::vector&)
,它就可以正常工作了

任何在其命名空间中定义了自由函数
load(istream&,X&)
的类X都将调用该函数

否则,任何具有
.load(istream&)
方法的类都将调用该方法

任何带有
istream&>>X&
重载的类X都将在上述所有操作都失败时被调用


.

如果您使用加载函数而不是加载类型,您可以获得ADL自定义作为奖励。@Yakk,是的,尽管这可能并不总是可取的,但我认为这里的
void\t
类有问题。我试图全面测试您的实现:替换我原来的
ForwardArgs()(is,args…)带有
PassArgs()(is,args…)T*create(std::istream&is,Args&…Args)
函数中的code>,它不会编译。@prestokeys
templatestruct voider{using type=void;};模板使用void\u t=typename voider::type
void\t
的一个变体,可在更多编译器上运行。标准中存在一个歧义,该歧义已被解决,使得
模板使用void\u t=void在一些较旧的编译器中不起作用。一个小问题是:以这种方式实现
PassArg
会使部分专门化变得很困难。我将当前版本重命名为,比如说,
PassArgImpl
,并添加一个
模板struct PassArgPassArgImpl
的code>。
// General case.
template <typename First, typename... Rest>
  struct PassArgs : PassArgs<Rest...> {
    void operator()(std::istream& is, First& first, Rest&... rest) const
    {
        PassArg<First>::pass(is, first);
        PassArgs<Rest...>::operator()(is, rest...);
    }
};
template<>
  struct PassArg<std::string, false>
  {
    static void pass(std::istream& is, std::string& s)
    { getline(is, s); }
  };
PassArgs<Args...>()(is, args...);
PassArgs<Rest...>::operator()(is, rest...);
PassArgs<Rest...>::sensible_name(is, rest...);
struct Thing {
  int a, b;
  friend void load (std::istream& is, Thing& t) {is >> std::skipws >> t.a >> t.b;}
};
struct Object {
  int a, b, c;
  void load (std::istream& is) {is >> std::skipws >> a >> b >> c;}
};
namespace meta {
  namespace details {
    template<template<class...>class Z, class=void, class...Ts>
    struct can_apply : std::false_type {};
    template<template<class...>class Z, class...Ts>
    struct can_apply<Z, decltype((void)(std::declval<Z<Ts...>>())), Ts...>:
      std::true_type
    {};
  }
  template<template<class...>class Z, class...Ts>
  using can_apply = details::can_apply<Z,void,Ts...>;
}
template<class T>
using member_load = decltype( std::declval<T>().load(std::declval<std::istream&>()) );

template<class T>
using stream_load = decltype( std::declval<std::istream&>() >> std::declval<T>() );
template<class T>
using has_member_load = meta::can_apply< member_load, T >;
template<class T>
using has_stream_load = meta::can_apply< stream_load, T >;
namespace loading {
  void load(std::istream&is, std::string& s) {
    while (std::getline (is, s) && s.empty());
  }
  template<class T>
  std::enable_if_t<has_member_load<T&>::value>
  load(std::istream&is, T& t) {
    t.load(is);
  }
  // uses ... to keep lowest priority:
  template<class T>
  std::enable_if_t<has_stream_load<T&>::value>
  load(std::istream& is, T& t, ...) {
    is >> t;
  }

  template<class...Ts>
  void load_many(std::istream&is, Ts&...ts) {
    using discard=int[];
    (void)discard{0,((
      load(is, ts)
    ),void(),0)...};
  }
}