繁体   English   中英

部分特化和对 std::void_t<> 的需求

[英]Partial specialization and the need for std::void_t<>

语言律师之一......

我在玩 SFINAE 和 TMP,试图获得更深入的理解。

考虑下面的代码,一个 std::is_default_constructible 的简单实现

#include <type_traits>

template <typename T, typename = void> struct is_default_constructable : std::false_type {};
template <typename T> struct is_default_constructable<T, decltype(T()) > : std::true_type {};

class NC { NC(int); };  // Not default constructable

#include <iostream>
int main(int, char **)
{
    std::cout << "int is_default_constructible? " << is_default_constructable<int>() << std::endl;
    std::cout << "NC is_default_constructible? " << is_default_constructable<NC>() << std::endl;
}

这编译得很好,但实际上不起作用,它对所有类型都返回 false。

对于 NC 情况,正如我所期望的那样, T()格式不正确,因此由于 SFINAE 丢弃了专业化并使用了主要模板 (false_type)。 但是对于int情况,我希望将专业化用作decltype(T())是有效的并且等效于T

如果根据<type_traits>的实际代码,我将专业化更改为

template <typename T> using wrap = void;
template <typename T> struct is_default_constructable<T, wrap<decltype(T())> > : std::true_type {};

std::void_t<>第二个模板参数包装在std::void_t<>的模型中,这迫使第二个类型为void ),这按预期工作。

更奇怪的是,使用void以外的类型作为主模板或wrap<>的默认类型的这种方案的变体也会失败,除非这两种类型相同。

有人可以解释为什么wrap<>的类型和第二个模板参数默认类型需要相同才能选择专业化吗?

(我在 g++ 6.3 版中使用“g++ -Wall --std=c++17”,但我认为这与编译器无关。)

这不是 SFINAE 或部分专业化排序的结果,而是由于使用了默认模板参数。 非正式地,原因是默认模板参数的应用发生搜索模板定义之前,包括可能的特化。

所以在上面的例子中,说is_default_constructable<int>的代码实际上是在应用默认的第二个参数后请求实例化模板is_default_constructable<int, void> 然后考虑可能的定义。

“主要”模板定义明确匹配并包含在内。 给定的部分专业化

template <typename T> struct is_default_constructable<T, decltype(T()) > : std::true_type {};

实际上是定义is_default_constructable<int, int> ,它与请求的is_default_constructable<int, void>不匹配is_default_constructable<int, void>因此即使替换成功,也会忽略特化。 这将主要定义(继承 false_type)作为唯一可行的定义,因此它被选中。

当专业化具有wrap<> (或std::void_t<> )以强制第二个 arg 为void ,专业化定义is_default_constructable<int, void>与请求匹配。 这个定义(假设替换成功,即T()格式良好)比主要定义更专业(根据超复杂的专业化排序规则),所以选择它。

顺便说一句,当 T 是引用类型或其他极端情况时,上述幼稚的实现可能无法按预期工作,这是使用所有这些标准库版本的一个很好的理由。 他们标准委员会的人比我聪明得多,并且已经想到了所有这些事情。

这个答案这个对有些相关问题的答案有更详细的信息让我正确。

而且,是的,我无法拼写可构造的,假设它甚至是一个单词。 这是使用标准库的另一个很好的理由。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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