选择继承运算符与 C++ 中的“using”子句相反

Fed*_*dor 10 c++ lambda operator-overloading multiple-inheritance language-lawyer

在下面的示例中, structS继承自两个函数对象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?
}
Run Code Online (Sandbox Code Playgroud)

正如我所料,这段代码被 MSVC 拒绝并出现错误:

error C2064: term does not evaluate to a function taking 0 arguments
Run Code Online (Sandbox Code Playgroud)

因为A::operator(int)确实需要 1 个参数,因此B::operator()不予考虑。

然而,GCC 和 Clang 都接受代码并B::operator()调用static_assert. 演示: https: //gcc.godbolt.org/z/x6x3aWzoq

这里是哪个编译器?

T.C*_*.C. 4

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

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

您可以通过实际编译s();禁用优化的调用来看到这一点;将发出对转换函数的调用。


IIRC MSVC 的 lambda 具有多个到函数指针的转换函数,适用于所有不同的调用约定,这使得重载解析不明确。