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++ 指定参数类型中是否存在POD结构成员的模板函数_C++_Templates_C++11_Sfinae - Fatal编程技术网

C++ 指定参数类型中是否存在POD结构成员的模板函数

C++ 指定参数类型中是否存在POD结构成员的模板函数,c++,templates,c++11,sfinae,C++,Templates,C++11,Sfinae,给定POD结构的一般形式 struct case_0 { const char *foo; }; struct case_1i { const char *foo; int v0; }; struct case_1d { const char *foo; double v0; }; struct case_2ii { const char *foo; int v0; int v1;

给定POD结构的一般形式

struct case_0   { const char *foo;                       };
struct case_1i  { const char *foo; int v0;               };
struct case_1d  { const char *foo; double v0;            };
struct case_2ii { const char *foo; int v0;    int v1;    };
struct case_2id { const char *foo; int v0;    double v1; };
// etc
是否可以根据
v0
v1
等数据成员的存在或不存在,向函数重载集的(模板)成员分派数据(理想情况下,不依赖于这些成员的特定类型),如果是,如何分派?具体地说,给定

void
process(const case_0& c)
{
   do_stuff_with(c.foo);
}

template <typename case_1> void   
process(const case_1& c)
{
   do_stuff_with(c.foo, c.v0);
}

template <typename case_2> void
process(const case_2& c)
{
   do_stuff_with(c.foo, c.v0, c.v1);
}
void
过程(const case_0&c)
{
用(c.foo)做东西;
}
模板空隙
过程(施工案例1和c)
{
用(c.foo,c.v0)填充;
}
模板空隙
过程(施工案例2&c)
{
用(c.foo,c.v0,c.v1)填充;
}
我希望为所有
case.*
结构选择每个重载,这些结构具有在其主体中使用的所有
v-
成员,并且——同样重要的是——没有任何未在其主体中使用的
v-
成员


这个程序必须是100%独立的,所以请不要升级。C++11功能还可以。

您需要编写一组特性,例如
has_v0
has_v1
(我确信已经多次演示过这一点),然后使用它们约束重载:

template <typename case_0,
  typename = typename std::enable_if<!has_v0<case_0>::value>::type,
  typename = typename std::enable_if<!has_v1<case_0>::value>::type
>
void
process(const case_0& c)
{
   do_stuff_with(c.foo);
}

template <typename case_1,
  typename = typename std::enable_if<has_v0<case_1>::value>::type,
  typename = typename std::enable_if<!has_v1<case_1>::value>::type
>
void   
process(const case_1& c)
{
   do_stuff_with(c.foo, c.v0);
}

template <typename case_2,
  typename = typename std::enable_if<has_v0<case_2>::value>::type,
  typename = typename std::enable_if<has_v1<case_2>::value>::type
>
void
process(const case_2& c)
{
   do_stuff_with(c.foo, c.v0, c.v1);
}
template::type,
typename=typename std::enable_if::value>::type
>
无效的
过程(const case_0&c)
{
用(c.foo)做东西;
}
模板::类型
>
无效的
过程(施工案例1和c)
{
用(c.foo,c.v0)填充;
}
模板
无效的
过程(施工案例2&c)
{
用(c.foo,c.v0,c.v1)填充;
}
您可以使用以下方法简化约束:

template<typename Cond>
  using Require = typename std::enable_if<Cond::value>::type;
模板
使用Require=typename std::enable_if::type;
e、 g

模板
无效的
过程(施工案例2&c)
{
用(c.foo,c.v0,c.v1)填充;
}

一个解决方案是@Jonathan Wakely提供的,它使用了
has_XXX
元函数

这里是另一个解决方案,但它要求您将完整的结构定义更改为
std::tuple
的typedef

完整结构: 替换为typedefs结构,如下所示: 被替换为
一旦接受此设计更改,原始问题的解决方案将变得非常简单,如下所示:

template<size_t...>
struct seq{};

template<size_t M, size_t ...N>
struct genseq  : genseq<M-1,M-1, N...> {};

template<size_t ...N>
struct genseq<0,N...>
{
    typedef seq<N...> type;
};

template <typename ...Args, size_t ...N> 
void call_do_stuff_with(std::tuple<Args...> & tpl, seq<N...>)
{
    do_stuff_with(std::get<N>(tpl)...);
}

template <typename ...Args> 
void process(std::tuple<Args...> & tpl)
{
   const size_t N = sizeof ...(Args);
   call_do_stuff_with(tpl, typename genseq<N>::type());
}
模板
结构序列{};
模板
结构genseq:genseq{};
模板
结构genseq
{
typedef-seq-type;
};
模板

void call_do_stuff_with(std::tuple

在第一个
过程中是否缺少
模板
重载?@JonathanWakely只有一个
case_0
结构,因此它似乎没有必要,但如果它有助于解决问题,我当然可以添加它(也许是为了利用
std::enable_if
)啊,我明白了,我不明白问题的这一部分。当然,我的答案需要一个模板。为什么不为它们定义重载,为每个结构定义一个重载?它们只是少数几个结构!@Nawaz因为通常的原因,人们编写模板函数,而不是写出所有可能的重载:具有
v0
但不是
v1
是无界的,类似于
v0
v1
但不是
v2
,等等。为什么不包括
has_v1
的实现呢?对于快速版本:
模板结构有_v1:std::false_type{};模板结构有_v1;:type>:std::true{}std::tuple
就是POD。看到这个:我不能写
std::tuple triples[]={{1,2,3},{4,5,6}(我得到编译错误:“使用初始值设定项列表初始化非聚合类型”)。因此,无论
std::tuple
是否应该是POD,对于当前编译器实现的这个应用程序来说,它还不够POD。附录:即使这样做有效(没有触发编译错误),我希望当前编译器为它生成静态构造函数,这对于这个应用程序来说也是不可接受的。(上述机器生成的代码包括这些结构数组的初始值设定项列表,其中包含数万个元素。它已经是一个2MB的对象文件。静态构造函数将增加数量级。)@Zack:您可以编写:
std::tuple triples[]={std::make_tuple(1,2,3),std::make_tuple(4,5,6)}。我认为这更具可读性,因为它清楚地显示了一个元组对象的构成。这是我所问问题的一个很好的解决方案,将来可能会对其他人有所启发。
struct case_0   { const char *foo;                       };
struct case_1i  { const char *foo; int v0;               };
struct case_1d  { const char *foo; double v0;            };
struct case_2ii { const char *foo; int v0;    int v1;    };
struct case_2id { const char *foo; int v0;    double v1; };
typedef std::tuple<const char*>            case_0;
typedef std::tuple<const char*,int>        case_1i;
typedef std::tuple<const char*,double>     case_1d;
typedef std::tuple<const char*,int,int>    case_2ii;
typedef std::tuple<const char*,int,double> case_2id;

template<typename...Args>
auto foo(std::tuple<Args...> & tpl) -> decltype(std::get<0>(tpl))&
{
     return std::get<0>(tpl);
}

template<typename...Args>
auto v0(std::tuple<Args...> & tpl) -> decltype(std::get<1>(tpl))&
{
     return std::get<1>(tpl);
}

template<typename...Args>
auto v1(std::tuple<Args...> & tpl) -> decltype(std::get<2>(tpl))&
{
     return std::get<2>(tpl);
}
case_1i obj; //full-fledge struct
obj.foo = "hello";
obj.v0 = 100;
case_1i obj; //typedef struct
foo(obj) = "hello";
v0(obj) = 100;
template<size_t...>
struct seq{};

template<size_t M, size_t ...N>
struct genseq  : genseq<M-1,M-1, N...> {};

template<size_t ...N>
struct genseq<0,N...>
{
    typedef seq<N...> type;
};

template <typename ...Args, size_t ...N> 
void call_do_stuff_with(std::tuple<Args...> & tpl, seq<N...>)
{
    do_stuff_with(std::get<N>(tpl)...);
}

template <typename ...Args> 
void process(std::tuple<Args...> & tpl)
{
   const size_t N = sizeof ...(Args);
   call_do_stuff_with(tpl, typename genseq<N>::type());
}