[英]How do I enable_if a struct depending on a condition and how many arguments?
我想创建一个元函数,如果将一个以上的参数传递给它,则返回某种类型;如果仅将一个参数传递给它,则根据条件返回另一种类型。 该条件是任意的,因此将需要一个enable_if
或类似类型的东西,但在本示例中,我将其enable_if
类型比较。 让我们简化为以下内容
int
,则返回bool
double
,则返回int
double
为此,我尝试执行以下操作:
#include <type_traits>
template <typename Enable, typename...Args>
struct Get;
// multiple arguments; return double regardless of the condition
template <typename FirstArg, typename... OtherArgs>
struct Get<typename std::enable_if<true>::type, FirstArg, OtherArgs...>
{
using type = double;
};
// single int; return bool
template <typename Arg>
struct Get<typename std::enable_if<std::is_same<Arg, int>::value>::type, Arg>
{
using type = double;
};
// single double; return int
template <typename Arg>
struct Get<typename std::enable_if<std::is_same<Arg, double>::value>::type, Arg>
{
using type = int;
};
int main()
{
static_assert(std::is_same<typename Get<double>::type, int>::value, "");
static_assert(std::is_same<typename Get<int>::type, bool>::value, "");
static_assert(std::is_same<typename Get<bool, int>::type, double>::value, "");
return 0;
}
输出:
prog.cpp: In function 'int main()': prog.cpp:29:51: error: 'type' in 'struct Get<double>' does not name a type static_assert(std::is_same<typename Get<double>::type, int>::value, ""); ^ prog.cpp:29:60: error: template argument 1 is invalid static_assert(std::is_same<typename Get<double>::type, int>::value, "");
我将不胜感激,因为它能教给我一个答案, 为什么它不能按我预期的方式工作,而不仅仅是如何解决它。 我正在努力寻找有关模板元编程的良好资源,到目前为止,我一直很随意地进行编程,这是我非常想解决的问题!
该template
参数的特化不是模板参数的原始定义。
对应于原始定义的名称位于template
名称之后。
专业化的template<>
部分中的参数是为匹配专业化而引入的类型。
所以原来的定义:
template <typename Enable, typename...Args>
struct Get;
1个或多个类型参数。 并且,除非专业匹配,否则未定义。
第一专业化:
template <typename FirstArg, typename... OtherArgs>
struct Get<typename std::enable_if<true>::type, FirstArg, OtherArgs...> {
using type = double;
};
好吧, std::enable_if<true>::type
只是void
,因此与以下内容相同:
template <typename FirstArg, typename... OtherArgs>
struct Get<void, FirstArg, OtherArgs...> {
using type = double;
};
因此,如果第一个类型为void
,并且至少还有一个其他类型,则此匹配。
第二专业化:
template <typename Arg>
struct Get<typename std::enable_if<std::is_same<Arg, int>::value>::type, Arg> {
using type = double;
};
因此,如果有两种类型,它将尝试匹配。 第二个是模式匹配。
如果不是int
,则第一个SFINAE失败。 如果它是一个int
,第一个最终被void
。 因此,这仅匹配Get<void, int>
。
第三专业化:
template <typename Arg>
struct Get<typename std::enable_if<std::is_same<Arg, double>::value>::type, Arg> {
using type = int;
};
同样,它匹配Get<void, double>
。
专业是模式匹配。 SFINAE enable_if
子句无法进行模式匹配。 因此,运行模式匹配,然后评估enable_if
子句。 如果它们失败,则专业化将不匹配。 如果它们成功,则enable_if
子句产生一个类型。 生成所有类型(不是模式)之后,类型的结果列表要么匹配,要么不匹配。
使用此机制的简单方法包括将您的公共版本转发到详细信息,将void
作为第一种类型传递,并在那里进行enable_if
工作。
另一种方法是将类型捆绑为类型列表,例如template<class...>struct types{};
,并将其作为一个参数传递,并将void
作为第二个参数传递,然后对该void
再次执行SFINAE。
这是一个例子:
namespace details {
template<class...>struct types{};
template<class Types, class=void>
struct foo;
template<class T0, class... Ts>
struct foo<types<T0, Ts...>,typename std::enable_if<
std::is_same<T0, int>::value && (sizeof...(Ts)>=1)
>> {
using type=double;
};
}
template<class T0, class... Ts>
struct foo:details::foo< details::types<T0, Ts...> >{};
details::foo
模式的特殊化与types
包匹配。 它使用那些模式匹配的类型执行enable_if
逻辑。 当且仅当第一种类型为int
且存在一种或多种其他类型(用于任意测试集)时, enable_if
通过。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.