c++ - 传递空初始值设定项列表时使用右值和左值引用候选者重载分辨率
问题描述
struct Foo {};
struct Bar {};
int Baz(const Foo&) { return 0; }
int Baz(Bar&&) { return 1; }
int main()
{
return Baz({});
}
这个称呼有歧义吗?MSVC 选择右值引用重载。GCC 说这是模棱两可的。int Baz(std::vector<Bar>&&)
Clang 也选择右值引用,但如果它不是,或者如果 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-qualifier,也S1
将右值引用绑定到右值并S2
绑定左值引用...
所以 GCC 在这里是错误的。
实际上,可以通过在结构中添加默认构造函数来类似地欺骗 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&&)
重载的编译器,demo:https ://gcc.godbolt.org/z/sMcx9ro1x
推荐阅读
- angular - 如何使用电子邮件在firebase数据库中添加自定义数据+通过角度的firebase身份验证
- javascript - JavaScript - 从同一对象中的函数内部调用嵌套函数
- python - 在 Python 中加密私钥
- kubernetes - 用于挂载卷的 Jenkinsfile 模板
- json - json中一个var的多个值
- javascript - 从字符串中提取每个单词而不在末尾获得额外的空值
- css - 背景颜色适用于 chrome 而不是 Firefox
- bash - Bash 脚本适用于一个文件,无法扩展想法
- python - Python:返回条件的函数参数
- android - 无法使用 react-native 在 Android 上以绝对位置渲染视图