[英]How do I enable_if a struct depending on a condition and how many arguments?
I want to create a meta function that returns a certain type if more than 1 argument is passed to it, and another type based on a condition if only a single argument is passed to it. 我想创建一个元函数,如果将一个以上的参数传递给它,则返回某种类型;如果仅将一个参数传递给它,则根据条件返回另一种类型。 The condition is arbitrary so it will require an enable_if
or something of that kind, but for this example I'll just make it a type comparison. 该条件是任意的,因此将需要一个enable_if
或类似类型的东西,但在本示例中,我将其enable_if
类型比较。 Let's simplify it to the following 让我们简化为以下内容
int
, return bool
如果传递了单个参数并且该参数是int
,则返回bool
double
, return int
如果传递了单个参数而该参数是double
,则返回int
double
如果传递了多个参数,则返回double
To achieve this I have tried to do the following: 为此,我尝试执行以下操作:
#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;
}
Output: 输出:
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, "");
I would be grateful for an answer that teaches me why this doesn't work the way I expected, not just how to fix it. 我将不胜感激,因为它能教给我一个答案, 为什么它不能按我预期的方式工作,而不仅仅是如何解决它。 I'm struggling to find good resources on template meta-programming and have so far been programming rather haphazardly, which is something I'd very much like to fix! 我正在努力寻找有关模板元编程的良好资源,到目前为止,我一直很随意地进行编程,这是我非常想解决的问题!
The template
arguments to a specialization are not the template arguments to the original definition. 该template
参数的特化不是模板参数的原始定义。
The ones that correspond to the original definition are after the template
name. 对应于原始定义的名称位于template
名称之后。
The arguments in the template<>
part of the specialization are the types introduced to match the specialization. 专业化的template<>
部分中的参数是为匹配专业化而引入的类型。
So original definition: 所以原来的定义:
template <typename Enable, typename...Args>
struct Get;
1 or more type arguments. 1个或多个类型参数。 And, unless a specialization matches, not defined. 并且,除非专业匹配,否则未定义。
First specialization: 第一专业化:
template <typename FirstArg, typename... OtherArgs>
struct Get<typename std::enable_if<true>::type, FirstArg, OtherArgs...> {
using type = double;
};
well, std::enable_if<true>::type
is just void
, so this is the same as: 好吧, std::enable_if<true>::type
只是void
,因此与以下内容相同:
template <typename FirstArg, typename... OtherArgs>
struct Get<void, FirstArg, OtherArgs...> {
using type = double;
};
So this matches if the first type is void
, and there is at least one other type. 因此,如果第一个类型为void
,并且至少还有一个其他类型,则此匹配。
Second specialization: 第二专业化:
template <typename Arg>
struct Get<typename std::enable_if<std::is_same<Arg, int>::value>::type, Arg> {
using type = double;
};
So this tries to match if there are two types. 因此,如果有两种类型,它将尝试匹配。 The second one is pattern matched. 第二个是模式匹配。
If it isn't int
, the first one SFINAE fails. 如果不是int
,则第一个SFINAE失败。 If it is an int
, the first one ends up being void
. 如果它是一个int
,第一个最终被void
。 So this matches Get<void, int>
only. 因此,这仅匹配Get<void, int>
。
Third specialization: 第三专业化:
template <typename Arg>
struct Get<typename std::enable_if<std::is_same<Arg, double>::value>::type, Arg> {
using type = int;
};
similarly, this matches Get<void, double>
. 同样,它匹配Get<void, double>
。
Specialization is pattern matching. 专业是模式匹配。 SFINAE enable_if
clauses cannot be pattern matched. SFINAE enable_if
子句无法进行模式匹配。 So the pattern match runs, then the enable_if
clauses are evaluated. 因此,运行模式匹配,然后评估enable_if
子句。 If they fail, the specialization does not match. 如果它们失败,则专业化将不匹配。 If they succeed, the enable_if
clause produces a type. 如果它们成功,则enable_if
子句产生一个类型。 After all types are generated (pattern and not), the resulting list of types either matches or does not. 生成所有类型(不是模式)之后,类型的结果列表要么匹配,要么不匹配。
The easy ways to use this machinery include having your public version forward to a details one, passing void
as the first type, and doing your enable_if
work there. 使用此机制的简单方法包括将您的公共版本转发到详细信息,将void
作为第一种类型传递,并在那里进行enable_if
工作。
Another way is to bundle your types up into a list of types, like template<class...>struct types{};
另一种方法是将类型捆绑为类型列表,例如template<class...>struct types{};
, and pass that as one argument, and void
as the second argument, and do SFINAE again on that void
. ,并将其作为一个参数传递,并将void
作为第二个参数传递,然后对该void
再次执行SFINAE。
Here is an example: 这是一个例子:
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...> >{};
The specialization of details::foo
pattern matches the types
bundle. details::foo
模式的特殊化与types
包匹配。 It does the enable_if
logic with those pattern matched types. 它使用那些模式匹配的类型执行enable_if
逻辑。 The enable_if
passes if and only if the first type is an int
and there are 1 or more additional types (for an arbitrary set of tests). 当且仅当第一种类型为int
且存在一种或多种其他类型(用于任意测试集)时, enable_if
通过。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.