【问题标题】:SFINAE on constructors works in VC2017 but not in clang/gcc [duplicate]构造函数上的 SFINAE 在 VC2017 中有效,但在 clang/gcc 中无效 [重复]
【发布时间】:2018-03-18 02:51:48
【问题描述】:
#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::enable_if' 中没有名为 'type' 的类型; 'enable_if' 不能用于禁用此声明

clang/gcc 对另一个 ctor 的实例化是不正确的,因为它应该在可能的重载列表中,对吧?

但在我提交错误之前,我想先了解一下其他人的想法。可能我没听懂……

【问题讨论】:

  • 你可以通过引入直接上下文来解决它:template&lt;bool B = b, typename = std::enable_if_t&lt;B&gt;&gt;
  • @PiotrSkotnicki:太棒了。请将其发布为答案。

标签: c++ c++14


【解决方案1】:

这是 MSVC 中的一个错误; clang 和 gcc 是对的。

问题在于 SFINAE 仅在重载解决期间发生,而不是之前发生。我的意思是,如果函数在你调用它之前格式不正确,那就是一个错误。

例如,当您使用S&lt;true&gt; 时,整个类都会被实例化。它看起来有点像这样:

struct S_true
{
    template<typename = void>
    S() {}

    template<typename = /*fail*/>
    S(int) {}
};

如您所见,第二个构造函数是完全错误的,它不是一个有效的定义,因为没有找到类型type(因为std::enable_if)。所以 SFINAE 甚至不能启动,类定义是错误的和诊断的。

您需要使模板参数b 成为两个构造函数的模板参数列表的一部分(看看@bolov 的答案)。

【讨论】:

  • 如果您愿意,可以将我的答案合并到您的答案中(无需署名),我会删除我的。
  • 感谢大家的这些即时答复!甚至我都不相信 clang/gcc 做错了,而 VC 做对了。看来我需要向 Microsoft 报告此错误。
  • @bolov 不,我不知道这种技术 :) 谢谢
  • @bolov 我很好奇:根据 C++17 17.7.8.1(最新草案),如果模板特化无效但未实例化(“ill-形成,无需诊断”)。对于 S,S(int) 的成员函数模板特化无效但未实例化,因为调用了 S()。对于 S 无效的 S() 不会被实例化,因为 S(int) 被调用。那么不报错真的是VC的bug吗?我很怀疑。你怎么看?
  • @xy 我不知道,没有仔细研究,但我的感觉是所有的 ctor 都需要实例化才能解决重载问题。如果是这种情况,那么它应该发出警告,并且不这样做是一个 VS 错误。我可能错了所有需要实例化的ctors,在这种情况下VS将符合不发出错误。
【解决方案2】:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-12-08
    • 2014-01-13
    • 1970-01-01
    • 2018-08-02
    • 2014-09-08
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多