结合void_t和enable_if?

时间:2018-03-01 08:24:25

标签: c++17 template-meta-programming sfinae enable-if void-t

C++17中,void_t允许使用class / struct模板轻松执行SFINAE:

template <class T, class = void>
struct test {
    static constexpr auto text = "general case";
};

template <class T>
struct test<T, std::void_t<decltype(std::begin(std::declval<T>())>> {
    static constexpr auto text = "has begin iterator";
};

void_t内的内容是一种类型。我的问题是:当void_t内的内容是一种类型特征时,如何做同样的事情。使用enable_if效果很好:

template <class T>
struct test<T, std::void_t<std::enable_if_t<std::is_class_v<T>>> {
    static constexpr auto text = "is a class";
};

是否有更短/更优雅的方式来写这个,或“正确的方式”来实现它,真的要结合void_tenable_if

2 个答案:

答案 0 :(得分:2)

std::void_t的一个重点是可变量

// ................VVV  <- is variadic
template <typename ...>
using void_t = void;

因此,当您必须检查多种类型时,允许SFINAE工作,并且当只有其中一种类型失败时允许您软失败。

如果您只需要检查某个值,并且必须使用std::enable_if(或类似的类型特征)进行检查,我就不会看到与{{1}一起使用它的理由}。

所以,在你的例子中,&#34;正确的方式&#34; (恕我直言)避免使用std::void_t

std::void_t

同样在使用单template <class T> struct test<T, std::enable_if_t<std::is_class_v<T>> { static constexpr auto text = "is a class"; }; 的情况下,我更喜欢旧的方式(但我认为这是个人品味的问题)

decltype()

答案 1 :(得分:2)

您似乎不明白为什么std::void_t是必要的。让我们解决一下:))

在您的第一个示例中,如果您不使用std::void_t,则永远不会选择部分特化,因为decltype将评估为某些类型T而非{ {1}},因此它不会与部分特化相匹配,并且会回归到一般情况。现在,如果您知道函数将始终返回相同类型,则可以随时更改主模板中的默认参数,但这种方式更难以更改。 (您可以查看我提供给另一个问题的answer,这可能有助于理解这一点。)

这就是void被引入的原因。 std::void_t只是一种身份类型特征,无论如何都是std::void_t。这意味着在您的第一个示例中,无论void的评估结果如何,第二个模板参数都将为decltype,因此如果voiddecltype,则匹配并选择专门化良好的。

std::enable_if_t有效,默认为void当且仅当其中的条件评估为true时。这意味着std::enable_if_t 已经无论如何都会返回void,因此您无需std::void_t将其“转换”为void ,因为它已经是void