C++ 部分专业化和std的需要:void\u t<&燃气轮机;
一个是语言律师 我正在和SFINAE和TMP打交道,试图获得更深入的理解 考虑下面的代码,std::的一个简单实现是可构造的C++ 部分专业化和std的需要:void\u t<&燃气轮机;,c++,language-lawyer,partial-specialization,C++,Language Lawyer,Partial Specialization,一个是语言律师 我正在和SFINAE和TMP打交道,试图获得更深入的理解 考虑下面的代码,std::的一个简单实现是可构造的 #include <type_traits> template <typename T, typename = void> struct is_default_constructable : std::false_type {}; template <typename T> struct is_default_constructabl
#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;
}
(即,将第二个模板参数包装在std::void\u t
的实体模型中,强制第二个类型为void
),这将按预期工作
更奇怪的是,在主模板中使用void
以外的类型作为默认类型或wrap
作为默认类型的方案的变体也会失败,除非这两种类型相同
有人能解释一下为什么wrap
的类型和第二个模板参数default类型需要相同才能选择专门化吗
(我在g++6.3版中使用“g++-Wall--std=c++17”,但我认为这与编译器无关。)这不是SFINAE或部分专门化排序的结果,而是由于使用了默认模板参数。非正式地说,原因是默认模板参数的应用发生在搜索模板定义(包括可能的专门化)之前 因此,在上述情况下,表示
是默认的\u可构造的
的代码实际上是在应用默认的第二个参数后请求实例化模板是默认的\u可构造的
。然后考虑可能的定义
“主要”模板定义明确匹配并包含在内。
给定的部分特化
template <typename T> struct is_default_constructable<T, decltype(T()) > : std::true_type {};
模板结构是\u默认\u可构造的:std::true\u类型{};
实际上定义了与请求的is\u default\u constructable
不匹配的is\u default\u constructable
,因此即使替换成功,也会忽略专门化。
这使得主定义(继承false_类型)成为唯一可行的定义,因此选择它
当专门化使用换行
(或std::void\u t
)强制第二个参数为void
,则专门化将定义与请求匹配的是可构造的。此定义(假设替换成功,即T()
格式正确)比主定义更专业(根据排序专业化的超复杂规则),因此选择它
顺便说一句,当t是引用类型或其他特殊情况时,上述幼稚实现可能无法按预期工作,这是使用所有这些的标准库版本的一个很好的理由。标准委员会的人比我聪明得多,他们已经想到了所有这些事情
对于一些相关的问题,我有更详细的信息来帮助我纠正错误
是的,我不会拼写constructible,假设这是一个单词。这是使用标准库的另一个很好的理由
template <typename T> struct is_default_constructable<T, decltype(T()) > : std::true_type {};