当前位置: 首页 > 知识库问答 >
问题:

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

佟高澹
2023-03-14
struct Foo {};
struct Bar {};

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

int main()
{
  return Baz({});
}

这个电话含糊不清吗?MSVC选择右值引用重载。GCC表示这是不明确的。Clang也选择右值引用,但如果它是intbaz(std::vector),则不再选择

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

有人能解释一下为什么这一点适用或不适用:

[...]

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

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


共有1个答案

司寇羽
2023-03-14

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

标准转换顺序S1比标准转换顺序S2更好

...

  • S1S2是引用绑定(11.6.3),两者都不引用没有ref-限定符声明的非静态成员函数的隐式对象参数,并且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)的编译

 类似资料:
  • 这两个函数完全匹配。以下是该标准的引用: 标准转换序列S1是比标准转换序列S2更好的转换序列,如果 ... S1和S2是引用绑定(8.5.3),都不引用未使用ref限定符声明的非静态成员函数的隐式对象参数,S1将右值引用绑定到右值,S2将左值引用绑定。 这不意味着第二个更好吗? 更新: 有一个相关的问题。下面的代码是它的简化版本。

  • 考虑以下C 11代码: 这会产生一个错误: 我明白为什么,但我正试图从标准中的语言来证明这一点。 意译C 11 N34858.5.3.5: int的引用由int类型的表达式初始化,如下所示:(yes) 如果引用是右值引用:(是) 如果初始值设定项表达式:(是) 是xvalue、类prvalue、数组prvalue还是函数左值(否?),或 这两点都不适用吗?所以我们应该假设它是不正确的,因为两者都不

  • 我通过解决一些黑客等级问题来学习java。下面的代码是关于学习静态初始值设定项块的。例外情况是thown和Capture,但程序仍在运行,我不确定原因。 输入:-1,2 预期输出:java.lang.例外:宽度和高度必须为正 实际输出:宽度和高度必须为正-2

  • 我对Swift类有一个问题。我有UITableViewController类和UITableViewCell类的swift文件。我的问题是UITableViewCell类和网点。这个类有一个错误Class“HomeCell”没有初始化程序,我不明白这个问题。 感谢您的回复。

  • 我相信现代C初始值设定项列表对于初始化对象非常有用,甚至不需要定义自己的构造函数: 但是,当我的类从另一个类继承时,这不起作用: 我尝试添加

  • Ivor Horton在开始的Visual C 2013中提到了C语言中的“初始化列表”: "对于const或引用类型的类成员,您无法选择如何初始化它们。唯一的方法是在构造函数中使用成员初始化器列表。构造函数主体内的赋值将不起作用。" 我的Visual Studio 2012 express没有编译初始值设定项列表,所以一开始我很困惑,然后我意识到它不受支持。 我的问题是人们如何在初始化器列表之前