Fed*_*dor 10 c++ lambda operator-overloading multiple-inheritance language-lawyer
在下面的示例中, structS继承自两个函数对象A,B每个对象都有自己的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
这里是哪个编译器?
GCC(和 Clang)在这种情况下是正确的。
无捕获非泛型 lambda 具有到函数指针 ( [expr.prim.lambda.closure]/8 ) 的转换函数,该转换函数由 继承S(并且不会冲突,因为转换函数来自不同类型A并B转换为不同类型)。因此,在函数调用表达式(如 )的重载解析期间,为每个转换函数( [over.call.object]/2s() )引入代理调用函数。从 的转换函数引入的函数是唯一可行的候选者,因此它是通过重载决议选择的,并且通过首先转换为函数指针并调用它来执行调用。Bs
您可以通过实际编译s();禁用优化的调用来看到这一点;将发出对转换函数的调用。
IIRC MSVC 的 lambda 具有多个到函数指针的转换函数,适用于所有不同的调用约定,这使得重载解析不明确。