【发布时间】:2018-10-18 00:11:31
【问题描述】:
给语言律师一个....
我正在玩 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<> 的模型中,强制第二个类型为 void),这可以按预期工作。
更奇怪的是,这种方案的变体使用void 以外的类型作为主模板中的默认类型或wrap<> 也失败了,除非这两种类型相同。 p>
有人可以解释为什么wrap<> 的类型和第二个模板参数默认类型需要相同才能选择专业化吗?
(我在 g++ 6.3 版中使用“g++ -Wall --std=c++17”,但我认为这与编译器无关。)
【问题讨论】:
标签: c++ language-lawyer partial-specialization