传递空初始值设定项列表时使用右值和左值引用候选项的重载解析


struct Foo {};
struct Bar {};
int Baz(const Foo&) { return 0; }
int Baz(Bar&&) { return 1; }
int main()
{
return Baz({});
}

这个电话是模棱两可的吗?MSVC 选择右值引用重载。海湾合作委员会说这是模棱两可的。Clang 也选择右值引用,但如果它是int Baz(std::vector<Bar>&&)的,或者如果 Bar 得到一个采用 std::initializer_list 的构造函数,则不再选择右值引用。

{}Bar是标准转换序列吗?

有人可以解释为什么这适用或不适用:

  1. 标准转换序列 S1 优于标准转换序列 转换序列 S2 如果

[...]

c( 或者,如果不是这样,S1 和 S2 都绑定到引用参数到引用限定成员函数的隐式对象参数以外的内容,并且 S1 将右值引用绑定到右值,而 S2 将左值引用绑定到右值

(https://en.cppreference.com/w/cpp/language/overload_resolution(

正如问题中已经提到的,标准在[over.ics.rank]/(3.2(中说:

标准转化序列S1是比标准转化序列更好的转化序列S2

  • S1S2是引用绑定 (11.6.3(,并且都不引用在没有ref 限定符的情况下声明的非静态成员函数的隐式对象参数,并且S1将右值引用绑定到右值,S2绑定左值引用

所以海湾合作委员会在这里是错误的。

实际上,通过在结构中添加默认构造函数,Clang 也可以被类似地欺骗:

struct Foo {
constexpr Foo() = default;
};
struct Bar {
constexpr Bar() = default;
};
constexpr int Baz(const Foo&) { return 0; }
constexpr int Baz(Bar&&) { return 1; }
int main() {
static_assert( Baz({}) == 1 );
}

MSVC 是在此处正确选择重载Baz(Bar&&)编译器,演示:https://gcc.godbolt.org/z/sMcx9ro1x

相关内容

  • 没有找到相关文章