繁体   English   中英

如何根据条件和多少个参数启用结构?

[英]How do I enable_if a struct depending on a condition and how many arguments?

我想创建一个元函数,如果将一个以上的参数传递给它,则返回某种类型;如果仅将一个参数传递给它,则根据条件返回另一种类型。 该条件是任意的,因此将需要一个enable_if或类似类型的东西,但在本示例中,我将其enable_if类型比较。 让我们简化为以下内容

  1. 如果传递了单个参数并且该参数是int ,则返回bool
  2. 如果传递了单个参数而该参数是double ,则返回int
  3. 如果传递了多个参数,则返回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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM