为什么要通过右值引用而不是值来获取std::initializer_list?

19

我看到的大多数使用 std::initializer_list 的 C++11 代码都是按值传递,但有时会按右值引用传递。这样做有什么好处吗?

例如,我遇到的几乎每个示例都是这样做的:

class A {
  public:
  A(std::initializer_list<int>);
};

但我时常看到这样的做法:

class B {
  public:
  B(std::initializer_list<int> &&);
};

我大致了解右值引用的使用和目的,但是为什么在处理std::initializer_list时会更倾向于使用其中一种呢?我唯一能想到的是,class A允许初始化列表可被单独构造,而class B则不允许。

std::initializer_list<int> values {1,2,3,4};
A a(values); // valid
B b(values); // error

但我想不出为什么阻止那样做会是一件值得实现的好事情。

那么,为什么要通过右值引用获取std::initializer_list而不是按值传递呢?


3
可能仅仅是这样,有人真的想让你逐字逐句地传递这张清单... - Kerrek SB
好问题,我自己也在想。顺便说一下,我猜 B b(std::move(values)); 仍然可以编译。 - iavr
@zmb 每次我研究它时,似乎他们可以在这里使用传值方式并且它会起作用。但是C++11还很新,我不确定这是否是一种已知的惯用语,而我只是还没有弄清楚。 - wjl
2
我唯一的猜测是,作者可能认为按值传递初始化列表会使列表中的值不必要地复制。(这是不正确的 - 复制初始化列表并不会复制底层的值)。 - zmb
2
既然没有人提到它,那我就说一下:由initializer_list指定的元素是const的,因此即使该列表被rvalue接收,也无法从中移动。 - Casey
显示剩余2条评论
2个回答

9

我不确定是否有一个充分的理由,但我的猜测是,代码作者可能认为按值传递初始化器列表会使列表中的元素进行不必要的复制。当然,这是不正确的 - 复制初始化器列表不会复制其中的值。


4

std::initializer_list 即使按值传递,也体现了引用语义,因此通过引用传递最多只是误导性的(它仅包含非拥有指针)。

存在可以绑定到任何东西的通用引用,但它们不能通过大括号初始化列表语法(即 { x, y })进行初始化,因此通过这种方式获取 initializer_list 引用需要一些特殊情况的组合。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接