17

Can a std::initializer_list contain reference types (both rvalue and lvalue)? Or does one have to use pointers or a reference wrapper (such as std::ref)?

EDIT:

Perhaps more clarification is due:

I have a member variable, ::std::vector<std::function<void()> >, into which I would like to forward a lambda object. This would usually be accomplished with emplace_back, but I wanted to do it in the constructor's initialization list. Alas, as I read, this would make forwarding impossible.

2
  • 1
    You mean something like std::initializer_list<int&> a = {...};? Commented Jun 8, 2014 at 18:36
  • @RSahu Yeah, or &&, but I've had class reference types in mind mostly. Commented Jun 8, 2014 at 18:56

3 Answers 3

14

Can a std::initializer_list contain reference types (both rvalue and lvalue)?

std::initializer_list<T> doesn't hold references to its elements. It uses copy-semantics by holding its values as const objects:

18.9 Initializer List [support.initlist]

An object of type initializer_list<E> provides access to an array of objects of type const E.

An initializer_list of references will cause a compilation error because iternally pointers are used for iterators:

#include <initializer_list> int main() { int x; std::initializer_list<int&> l = {x}; // In instantiation of 'class std::initializer_list<int&>': // error: forming pointer to reference type 'int&' // typedef const _E* iterator; } 

An initializer_list also doesn't support move-semantics as const objects cannot be moved from. Holding your objects in a std::reference_wrapper<T> is the most viable solution if you wish to maintain reference-semantics.

Sign up to request clarification or add additional context in comments.

3 Comments

I believe they do support a kind of move semantics, as you technically can "move" a const &&.
@user1095108 No they don't. A move doesn't happen just from calling std::move(), it's simply a cast to an rvalue. A constructor taking a non-const rvalue reference (X&&) is where the movement actually happens, and "moving" a const object will actually create a copy in some cases, and in others a compilation error.
I know, but nothing prevents a move constructor from copying, instead of moving, either. I'm just nitpicking.
8

From http://www.cplusplus.com/reference/initializer_list/initializer_list/

initializer_list objects are automatically constructed as if an array of elements of type T was allocated

thus they can't be used with something like std::initializer_list<int&>. The reason is the same for which the following gives a compiler error

int& arr[20]; 

error: declaration of ‘arr’ as array of references

and that is dictated by the C++ standard: https://stackoverflow.com/a/1164306/1938163

2 Comments

So, I need to use a wrapper or pointers?
I'd say yes, something that you can allocate an array of.
3

You do not need list initialization here

As others mentioned, you cannot use std::initializer_list with references. You can use std::initializer_list<std::reference_wrapper<...>>, but it will prevent your from passing rvalues as arguments to the constructor, because std::reference_wrapper can only bind to lvalues. In other words, the following will not compile:

YourContainerOfFunctions C{ [](){} }; 

This makes usage of std::initializer_list in your case neither efficient nor convenient.

Use variadic templates instead!

I believe that is what you wanted to achieve:

class Foo { std::vector<std::function<void()>> Functions; public: template <class... FuncTs> Foo(FuncTs &&...Funcs) : Functions({std::forward<FuncTs>(Funcs)...}) {} }; void foo(){}; int main() { auto boo = []() {}; std::function<void()> moo = []() {}; Foo F{ foo, boo, // passed by reference, then copied []() {}, // moved, then copied std::move(moo) // moved, then also moved }; } 

This requires at most one copy per argument, necessary because std::function always make a copy of functor object which it is constructed from. An exception is construction of std::function from std::function of the same type

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.