构造函数上的SFINAE在VC2017中工作,但在clang / gcc中不起作用


#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的答案)。

@Rakete1111是

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) {}
};

相关内容

最新更新