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
是标准转换序列吗?
有人可以解释为什么这适用或不适用:
- 标准转换序列 S1 优于标准转换序列 转换序列 S2 如果
[...]
c( 或者,如果不是这样,S1 和 S2 都绑定到引用参数到引用限定成员函数的隐式对象参数以外的内容,并且 S1 将右值引用绑定到右值,而 S2 将左值引用绑定到右值
(https://en.cppreference.com/w/cpp/language/overload_resolution(
正如问题中已经提到的,标准在[over.ics.rank]/(3.2(中说:
标准转化序列
S1
是比标准转化序列更好的转化序列S2
。
S1
和S2
是引用绑定 (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