Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why take a std::initializer_list by rvalue reference vs. by value?

Most of the C++11 code that takes std::initializer_list I've seen takes it by value, but sometimes it is taken by rvalue reference. Is there any good reason to do this?

For example, almost every example I've come across does this:

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

But I keep seeing this done occasionally:

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

I understand the use and purpose of rvalue references in general, but why would one of these be preferred over the other in the case of a std::initializer_list? The only thing I could think of is that class A allows the initializer list to be constructed separately, and class B prevents this.

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

But I can't think of a good reason why preventing that would be a desirable thing to accomplish.

So, why would one take a std::initializer_list by rvalue reference instead of by value?

like image 750
wjl Avatar asked Feb 19 '14 00:02

wjl


People also ask

Why do we need Rvalue references?

Rvalue references is a small technical extension to the C++ language. Rvalue references allow programmers to avoid logically unnecessary copying and to provide perfect forwarding functions. They are primarily meant to aid in the design of higer performance and more robust libraries.

What is std :: Initializer_list?

std::initializer_list This type is used to access the values in a C++ initialization list, which is a list of elements of type const T .

Can Lvalue reference bind Rvalue?

An lvalue const reference can bind to an lvalue or to an rvalue. The syntax for a reference to an rvalue of type T is written as T&& . An rvalue reference refers to a movable value—a value whose contents we don't need to preserve after we've used it (for example, a temporary).


2 Answers

I'm not sure I have a good reason, but my guess would be that the author of the code may have thought that passing an initializer list by value would make unnecessary copies of the elements in the list. This is, of course, not true - copying an initializer list does not copy the underlying values.

like image 106
zmb Avatar answered Sep 21 '22 10:09

zmb


std::initializer_list embodies reference semantics even when passed by value, so passing by reference is at best misleading. (It only contains non-owning pointers.)

There are universal references which bind to anything, but they cannot be initialized by the braced-init-list syntax (i.e. { x, y }), so getting an initializer_list reference that way would take a combination of circumstances.

like image 38
Potatoswatter Avatar answered Sep 20 '22 10:09

Potatoswatter