[英]Variadically templated use of std::conditional where one type is an instantiation failure
I am attempting to build a variadically templated class. 我试图建立一个变量模板类。 As is common, each level of the instantiation needs to instantiate the "next level" by slicing off one type and then using the remainder.
通常,实例化的每个级别需要通过切掉一个类型然后使用余数来实例化“下一级”。 For my final level, rather than specialize on one type, I'd rather give some base case type and keep from duplicating the actual logic.
对于我的最终级别,而不是专注于一种类型,我宁愿给出一些基本案例类型,并避免重复实际逻辑。
I've added a std::conditional
to switch on the BaseCase
when the rest of the types consists of an empty parameter pack. 当其余类型包含一个空参数包时,我添加了一个
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
};
The problem is that VariadicClass
is templated on at least one type parameter, so when it hits the base case ( Ts
is empty), trying to use std::conditional
uses VariadicClass<>
, which fails of course. 问题是
VariadicClass
是至少一个类型参数的模板,所以当它遇到基本情况( Ts
为空)时,尝试使用std::conditional
使用VariadicClass<>
,当然这是失败的。
The solution I've managed is to write some specific functions and use decltype
along with overloads, and not use std::conditional
at all. 我管理的解决方案是编写一些特定的函数并使用
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>()...));
Now, this works, but if I want to keep up this practice every time I have a variadic class, it seems tedious. 现在,这是有效的,但如果我想每次有一个变量类时都要保持这种练习,那看起来很乏味。 Is there a way to use
std::conditional
or something similar to achieve this effect without having to write out so much problem-specific code? 有没有办法使用
std::conditional
或类似的东西来实现这种效果,而不必写出这么多特定于问题的代码?
Defer evaluation. 推迟评估。
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
ignores the Ts...
and returns its argument. identity
忽略Ts...
并返回其参数。 delay
takes a template
and applies the Ts...
. delay
采用template
并应用Ts...
While the signature looks suspicious, it works. 虽然签名看起来很可疑,但它确实有效。
Why not just 为什么不呢
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;
};
After reading TC's answer and Yakk's comment, I realized I could write this as one templated class with two specializations, rather than write another BaseClass
and the type alias. 在阅读了TC的答案和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
};
Alternatively, you may specialize VariadicClass<T>
或者,您可以专门化
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;
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.