变量模板化使用std :: conditional,其中一种类型是实例化失败

时间:2014-08-28 01:39:29

标签: c++ templates c++11 variadic-templates template-meta-programming

我正在尝试构建一个可变模板化的类。通常,实例化的每个级别需要通过切掉一个类型然后使用余数来实例化“下一级”。对于我的最终级别,而不是专注于一种类型,我宁愿给出一些基本案例类型,并且不要复制实际的逻辑。

我添加了std::conditional来启用BaseCase,其余类型包含空参数包。

class BaseCase { };

template <typename T, typename... Ts>
class VariadicClass;

template <typename... Ts>
using NextLevel = typename std::conditional<
    sizeof...(Ts) != 0, VariadicClass<Ts...>, BaseCase>::type;

template <typename T, typename... Ts>
class VariadicClass {
    T this_level; // whatever
    NextLevel<Ts...> next_level; // fails when Ts is empty
};

问题VariadicClass在至少一个类型参数上被模板化,因此当它遇到基本情况时(Ts为空),尝试使用{{ 1}}使用std::conditional,当然失败了。

我管理的解决方案是编写一些特定的函数并使用VariadicClass<>和重载,而不是使用decltype

std::conditional

现在,这是有效的,但是如果我想每次有一个可变的课程时都要保持这种练习,那似乎很乏味。有没有办法使用template <typename... Ts> VariadicClass<Ts...> type_helper(Ts&&...); BaseCase type_helper(); template <typename... Ts> using NextLevel = decltype(type_helper(std::declval<Ts>()...)); 或类似的东西来实现这种效果,而不必写出这么多特定于问题的代码?

4 个答案:

答案 0 :(得分:6)

推迟评估。

template<class T>struct identity{
  template<class...>using result=T;
};
template<template<class...>class src>
struct delay{
  template<class...Ts>using result=src<Ts...>;
};

template <typename... Ts>
using NextLevel =
typename std::conditional<
  sizeof...(Ts) != 0, delay<VariadicClass>, identity<BaseCase>
>::type::template result<Ts...>;

identity忽略Ts...并返回其参数。 delay需要template并应用Ts...。虽然签名看起来很可疑,但它确实有效。

答案 1 :(得分:4)

为什么不

class BaseCase { };

template <typename... Ts>
class VariadicClass; // undefined base template

template <typename... Ts>
using NextLevel = typename std::conditional<
    sizeof...(Ts) != 0, VariadicClass<Ts...>, BaseCase>::type;

template <typename T, typename... Ts>
class VariadicClass<T, Ts...> { // partial specialization for having at least 1 type parameter
    T this_level; // whatever
    NextLevel<Ts...> next_level;
};

答案 2 :(得分:2)

在阅读T.C.'s answer和Yakk的评论之后,我意识到我可以把它写成一个带有两个特化的模板化类,而不是写另一个BaseClass和类型别名。

template <typename... Ts>
class VariadicClass;

// specialization gets everything but an empty Ts
template <typename T, typename... Ts>
class VariadicClass<T, Ts...> {
    VariadicClass<Ts...> next_level;
    // normal case
};

template <>
class VariadicClass<> { // instead of class BaseCase
    // base case
};

答案 3 :(得分:0)

或者,您可以专攻VariadicClass<T>

class BaseCase {};

// general case
template <typename T, typename... Ts>
class VariadicClass {
    T this_level; // whatever
    VariadicClass<Ts...> next_level;
};

// specialization
template <typename T>
class VariadicClass<T> {
    T this_level; // whatever
    BaseClass next_level;
};