与 C++ 中的“using”子句相反的继承运算符的选择
Selection of inherited operator contrary to `using` clause in C++
在下面的示例中,struct S
继承自两个功能对象 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?
}
如我所料,此代码被 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), which is inherited by S
(and doesn't conflict since the conversion functions from A
and B
convert to different types). So during overload resolution for a function call expression like s()
, surrogate call functions are introduced for each conversion function ([over.call.object]/2)。从B
的转换函数中引入的是唯一可行的候选者,因此通过重载决议选择它,并通过先将s
转换为函数指针并调用它来执行调用。
您可以通过实际编译禁用优化的 s();
调用来看到这一点; a 将发出对转换函数的调用。
IIRC MSVC 的 lambda 有多个 转换函数到所有不同调用约定的函数指针,这使得重载解析不明确。
在下面的示例中,struct S
继承自两个功能对象 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?
}
如我所料,此代码被 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), which is inherited by S
(and doesn't conflict since the conversion functions from A
and B
convert to different types). So during overload resolution for a function call expression like s()
, surrogate call functions are introduced for each conversion function ([over.call.object]/2)。从B
的转换函数中引入的是唯一可行的候选者,因此通过重载决议选择它,并通过先将s
转换为函数指针并调用它来执行调用。
您可以通过实际编译禁用优化的 s();
调用来看到这一点; a 将发出对转换函数的调用。
IIRC MSVC 的 lambda 有多个 转换函数到所有不同调用约定的函数指针,这使得重载解析不明确。