#include <type_traits>
template<bool b>
struct S
{
template<typename = std::enable_if_t<b>>
S() {}
template<typename = std::enable_if_t<!b>>
S(int) {}
};
S<true> s{}; // error in clang/gcc, OK in VC2017
S<false> s{0}; // error in clang/gcc, OK in VC2017
在这两种情况下,clang/gcc 都尝试实例化由于 SFINAE 而实际上应该丢弃的 ctor。错误消息是:
错误:在"std::"中没有名为"type"的类型enable_if<false,>;"enable_if"不能用于禁用此声明
CLANG/GCC 对另一个 CTOR 的实例化是不正确的,因为它不应该在可能的重载列表中,对吧?
但在我提交错误之前,我想阅读其他人的想法。也许我做得不对...
这是 MSVC 中的一个错误; clang 和 gcc 是对的。
问题是 SFINAE 仅在过载解决期间发生,而不是在过载解决之前。我的意思是,如果函数在你调用它之前就格式不正确,那就是一个错误。
例如,当您使用 S<true>
时,将实例化整个类。它看起来有点像这样:
struct S_true
{
template<typename = void>
S() {}
template<typename = /*fail*/>
S(int) {}
};
如您所见,第二个构造函数的格式完全不正确,它不是一个有效的定义,因为找不到type
类型(因为std::enable_if
)。所以SFINAE甚至不能启动,类定义是格式不正确和诊断的。
您需要将模板参数b
两个构造函数的模板参数列表的一部分(看看@bolov的答案)。
100%正确的。
您需要使模板参数 bool b 成为模板的一部分 两个构造函数的参数列表。
这是如何做到这一点(这是一个非常标准的技术):
template<bool b>
struct S
{
template<bool bb = b, typename = std::enable_if_t<bb>>
S() {}
template<bool bb = b, typename = std::enable_if_t<!bb>>
S(int) {}
};