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

问题描述 投票:0回答:1

在下面的例子中,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 都接受代码并在

B::operator()
中调用
static_assert
。演示:https://gcc.godbolt.org/z/x6x3aWzoq

哪个编译器就在这里?

c++ lambda operator-overloading language-lawyer multiple-inheritance
1个回答
4
投票

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

A captureless nongeneric lambda has a conversion function to function pointer ([expr.prim.lambda.closure]/8), which is inherited by

S
(and doesn't conflict since the conversion functions from
A
and
B
转换为不同的类型)。因此,在像
s()
这样的函数调用表达式的重载决策期间,为每个转换函数 ([over.call.object]/2) 引入了代理调用函数。从
B
的转换函数中引入的是唯一可行的候选者,因此通过重载决议选择它,并通过先将
s
转换为函数指针并调用它来执行调用。

您可以通过在禁用优化的情况下实际编译

s();
调用来看到这一点;将发出对转换函数的调用。


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

© www.soinside.com 2019 - 2024. All rights reserved.