与c++中的' using '子句相反的继承操作符的选择



在下面的示例中,结构体S继承了两个函数对象AB,每个对象都有自己的operator (),然后声明using A::operator()A获取运算符:

using A = decltype([](int){ return 1; });
using B = decltype([](){ return 2; });
struct S : A, B {
using A::operator();
};
int main() {
S s;
static_assert( s() == 2 ); // passes in GCC and Clang, but why?
}
如我所料,这个代码被MSVC拒绝,错误如下:
error C2064: term does not evaluate to a function taking 0 arguments

因为A::operator(int)确实接受1个参数,所以B::operator()不被考虑。

但是GCC和Clang都接受这个代码并在static_assert中调用B::operator()。演示:https://gcc.godbolt.org/z/x6x3aWzoq

哪个编译器在这里?

GCC(和Clang)在这种情况下是正确的。

一个无捕获的非泛型lambda有一个到函数指针的转换函数([expr.prim.lambda.closure]/8),它被S继承(并且不冲突,因为AB的转换函数转换为不同的类型)。因此,在像s()这样的函数调用表达式的重载解析期间,为每个转换函数([over.call.object]/2)引入代理调用函数。从B的转换函数引入的指针是唯一可行的候选者,因此通过重载解析选择它,并通过首先将s转换为函数指针并调用它来执行调用。

你可以通过编译一个禁用优化的s();调用看到这一点;将触发对转换函数的调用。


IIRC MSVC的lambdas有多个转换函数到所有不同调用约定的函数指针,这使得重载解析有歧义。

相关内容

  • 没有找到相关文章

最新更新