同时从 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
我的问题:
- 谁是对的? Clang 还是 GCC?
- 如何获取代码以使用 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);
}
我认为 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/