c++ - Clang 与 GCC : Error in unevaluated context breaks SFINAE

标签 c++ templates gcc sfinae clang++

同时从 my previous question 继续工作,我遇到了 clang 和 GCC 的不同行为。
我需要检查成员函数指针,因为我需要知道该函数是否被继承。

在 SFINAE 上下文中比较成员函数指针时,成员函数 Foo::foo() 存在,但其主体包含代码 (x.hello())最终不编译。

以下代码使用 clang 进行编译。 然而,GCC 似乎评估了 Foo::foo() 的函数体并以错误退出(“struct Caller”没有名为“hello”的成员),尽管在未评估的 SFINAE 上下文中(或者我希望如此)。

#include <iostream>
#include <type_traits>

struct Foo
{
    template <typename T> void foo(T&& x) { x.hello(); }
};

struct Caller
{    
    template <typename T>
    auto call(T&& x) -> decltype(
        std::enable_if_t<
            std::is_same<
                decltype(&T::template foo<decltype(*this)>),
                void (T::*)(decltype(*this))
            >::value
        >())
    {
        //x.foo(*this);
    }
};

int main()
{
  Caller c;
  c.call(Foo());
}

我测试了:

  • clang 3.8.0
  • g++ 6.1.0

两者的编译器选项:-std=c++14 -O2 -Wall -pedantic -pthread

live example

我的问题:

  1. 谁是对的? Clang 还是 GCC?
  2. 如何获取代码以使用 GCC 进行编译?

最佳答案

第二个问题的回答

How can I get the code to compile with GCC?

我会简化传递给 decltype() 的表达式。如果 call 方法的编译依赖于 x.foo(*this); 的编译,那么你应该使用它。

struct Foo
{
    template <typename T> void foo(T&& x) { x.hello(); }
};

struct Caller
{    
    template <typename T>
    auto call(T&& x, int) -> decltype(x.foo(*this))
    {
        //x.foo(*this);
    }
    template <typename T>
    void call(T&&, char){ std::cout << "hello" << std::endl;}
};

int main()
{
  Caller c;
  c.call(Foo(), 0);
}

Demo here.


我认为 OP 与 gcc 的问题在于正在获取函数的地址(如果没有明确获取,则衰减为函数指针)。我认为这是标准中的一个极端案例。如果需要 Foo::foo 方法,则 x.hello() 需要存在(编译);一般来说,获取某物的地址可以满足这一点,但在未评估的上下文中(decltype()),我不确定这是否适用 - 当然 clang 不需要它存在(MSVC 也不需要).

在这方面,

Who is right? Clang or GCC?

我怀疑 clang 实现了对标准的更宽松的阅读,并且可能更正确的阅读。 decltype() 的操作数是未计算的操作数,参见 [dcl.type.simple]/4 ;

The operand of the decltype specifier is an unevaluated operand (Clause [expr]).

关于c++ - Clang 与 GCC : Error in unevaluated context breaks SFINAE,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38371924/

相关文章:

c++ - 使用指针写入标准容器

jquery - ASP.NET MVC3 Razor 与 Html.Helpers 和 JQuery 模板的串联

c - 只读共享内存段错误

C:Var和Function同名——ld的bug?

c++ - gcc 看不到标准头文件

c++ - 如何以编程方式检测 PC 是否具有 USB3 功能?

c++ - 如何将模板构造函数特化移动到 cpp 文件?

c++ - 在 C++ 中迭代集合

c++ - 如果我没有显式实例化 g++(使用 -fno-implicit-templates)从哪里获取模板定义?

c++ - 非命名空间范围的显式特化