我正在尝试构建一个可变模板化的类。通常,实例化的每个级别需要通过切掉一个类型然后使用余数来实例化“下一级”。对于我的最终级别,而不是专注于一种类型,我宁愿给出一些基本案例类型,并且不要复制实际的逻辑。
我添加了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>()...));
或类似的东西来实现这种效果,而不必写出这么多特定于问题的代码?
答案 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;
};