19

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?

wjl
  • 7,519
  • 2
  • 32
  • 41
  • 3
    Well, it might be just that, someone really wants you to pass the list literally... – Kerrek SB Feb 19 '14 at 00:06
  • Good question, I was wondering myself. By the way, I guess `B b(std::move(values));` would still compile. – iavr Feb 19 '14 at 00:13
  • Silly question, perhaps - but does the implementation of the rvalue reference version in any of the places you've seen this give any clues? – zmb Feb 19 '14 at 00:16
  • @zmb Ever time I have looked into it, it seemed to *me* that they could have used pass-by-value here and it would have worked the same. But C++11 is new enough that I wasn't sure if this was a known idiom and I just haven't figured it out yet. – wjl Feb 19 '14 at 00:22
  • 2
    My only guess would be that the author may have thought that passing an initializer list by value would make unnecessary copies of the values in the list. (This is not true - copying an initializer list does not copy the underlying values). – zmb Feb 19 '14 at 00:24
  • @zmb That might make sense -- especially since people generally learn about `std::initializer_list` and rvalue references about the same time since they are both C++11 features. Maybe you want to turn your conjecture into an answer so I can accept it if no other good answers show up in the near future. I think the comments so far are convincing me that there is no real good reason to do this. – wjl Feb 19 '14 at 00:36
  • 2
    Since no one else has mentioned it, I'll go ahead and say that the elements designated by an initializer_list are `const` so even if the list is taken by rvalue you can't move from them. – Casey Feb 19 '14 at 00:44

2 Answers2

9

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.

zmb
  • 7,605
  • 4
  • 40
  • 55
4

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.

Potatoswatter
  • 134,909
  • 25
  • 265
  • 421