Emplacement of a vector with initializer list - c++

i have a std::vector<std::vector<double>> and would like to add some elements at the end of it so this was my trial:
std::vector<std::vector<double> > vec;
vec.emplace_back({0,0});
but this does not compile whereas the following will do:
std::vector<double> vector({0,0});
Why can't emplace_back construct the element at this position? Or what am i doing wrong?
Thanks for your help.

The previous answer mentioned you could get the code to compile when you construct the vector in line and emplace that.
That means, however, that you are calling the move-constructor on a temporary vector, which means you are not constructing the vector in-place, while that's the whole reason of using emplace_back rather than push_back.
Instead you should cast the initializer list to an initializer_list, like so:
#include <vector>
#include <initializer_list>
int main()
{
std::vector<std::vector<int>> vec;
vec.emplace_back((std::initializer_list<int>){1,2});
}

Template deduction cannot guess that your brace-enclosed initialization list should be a vector. You need to be explicit:
vec.emplace_back(std::vector<double>{0.,0.});
Note that this constructs a vector, and then moves it into the new element using std::vector's move copy constructor. So in this particular case it has no advantage over push_back(). #TimKuipers 's answer shows a way to get around this issue.

There are really two issues here: the numeric type conversion and template argument deduction.
The std::vector<double> constructor is allowed to use the braced list (even of ints) for its std::vector<double>(std::initializer_list<double>) constructor. (Note, however, that std::initializer_list<int> does not implicitly convert to std::initializer_list<double>)
emplace_back() cannot construct the element from the brace expression because it is a template that uses perfect forwarding. The Standard forbids the compiler to deduce the type of {0,0}, and so std::vector<double>::emplace_back<std::initializer_list<double>>(std::initializer_list<double>) does not get compiled for emplace_back({}).
Other answers point out that emplace_back can be compiled for an argument of type std::initializer_list<vector::value_type>, but will not deduce this type directly from a {} expression.
As an alternative to casting the argument to emplace_back, you could construct the argument first. As pointed out in Meyers' Item 30 (Effective Modern C++), auto is allowed to deduce the type of a brace expression to std::initializer_list<T>, and perfect forwarding is allowed to deduce the type of an object whose type was deduced by auto.
std::vector<std::vector<double> > vec;
auto double_list = {0., 0.}; // int_list is type std::initializer_list<int>
vec.emplace_back(double_list); // instantiates vec.emplace_back<std::initializer_list<double>&>
emplace_back adds an element to vec by calling std::vector<double>(std::forward<std::initializer_list<double>>(double_list)), which triggers the std::vector<double>(std::initializer_list<double>) constructor.
Reference: Section 17.8.2.5 item 5.6 indicates that the this is a non-deduced context for the purposes of template argument deduction under 17.8.2.1 item 1.
Update: an earlier version of this answer erroneously implied that std::initializer_list<int> could be provided in place of std::initializer_list<double>.

Related

C++ vector push_back empty braces

I've seen code like
struct A {
int m;
};
vector<A> vec;
vec.push_back({});
My question is:
What's the difference between vec.push_back({}); and vec.push_back(A{})? Why can we omit A in A{}?
What's the difference between vec.push_back({}); and vec.push_back(A{})?
There isn't any, in this case.
Why can we omit A in A{}?
You are instantiating a vector to hold A elements. Thus its overloaded push_back() methods will accept const A& and A&& input parameters. Modern C++ standards provide initialization rules that let the compiler deduce that {} used in those contexts will construct an A object, which is why you don't need to specify the type in A{} explicitly.
FYI, vector also has emplace_back() methods that you should use instead of pushing an empty {}:
vector<A> vec;
vec.emplace_back();

Initialization of std::array with std::initializer_list in constructor's initialization list [duplicate]

This question already has answers here:
How do I initialize a member array with an initializer_list?
(8 answers)
Closed 7 years ago.
Consider the following piece of code:
struct foo {
std::vector<int> v;
foo(std::initializer_list<int> L) : v{L} {}
};
The code above compiles fine and initializes v as expected. Now consider the following piece of code:
struct bar {
std::array<int, 3> a;
bar(std::initializer_list<int> L) : a{L} {}
};
The above piece of code gives a compile error.
error: no viable conversion from 'std::initializer_list' to 'int'
Searching the web I found that the "proper" way to initialize a member std::array with a std::list_initializer is to use reinterpret_cast in the following manner:
bar(std::initializer_list<int> L) : a(reinterpret_cast<std::array<int, 3> const&>(*(L.begin()))) {}
Q:
Why I can initialize a member std::vector with an std::initializer_list in the initialization list of a constructor but I can't a member std::array?
Is the work-around showed above with reinterpret_cast the proper way to initialize a member std::array with a std::initializer_list?
std::array was designed (in the Boost library) to support the braces initialization syntax with C++03. The only way to do that in C++03 was as a POD (plain old data) type, one with no constructors. Initializer lists were introduced in C++11, along with std::array, but std::array was not changed from its Boost version to use initializer lists. So, it's historical.
By the way, note that the reinterpret_cast is dangerous here because the initializer list may contain fewer items than the array.
a std::array is a thin wrapper around a C++ array, see it like
template<typename T, size_t N>
struct {
T data[N];
}
So it doesn't have any constructor able to cope with a std::initializer_list, you must stick with a vector or copy the elements with something else (like std::copy) in the constructor.
foo(std::initializer_list<int> L) : v{L} {}
std::vector has a constructor that accepts a std::initializer_list as input. You are thus initializing the vector itself, not any particular element of the std::vector.
bar(std::initializer_list<int> L) : a{L} {}
std::array does not have a constructor that accepts a std::initializer_list as input (in fact, it does not have any constructors at all, it can only be initialized through aggregate initialization). You are thus trying to initialize a specific element of the array, which is why the compiler complains that it cannot convert a std::initializer_list to an int.

Wrong std::vector constructor

I'm getting a strange error from Clang when compiling what should be a straightforward line of code.
This code produces an error:
size_t s = 5;
std::vector<double> bestScores{s, -1.0};
I'm simply trying to use constructor #2 to fill a new vector with five -1.0 values. The error I get is Non-constant expression cannot be narrowed from type 'size_type' (aka 'unsigned long') to 'double' in initializer list.
What is going on? This compiles fine:
std::vector<double> bestScores{5, -1.0};
Is it trying to use the initializer list constructor? I thought you needed two curly braces for that:
std::vector<double> bestScores{{5, -1.0}};
The issue is that you are constructing the vector using a brace-enclosed initialization list. That favours the std::initializer_list<T> constructor when applicable. In this case, the size_t, -1.0 list is compatible with std::initializer_list<double>, so that constructor gets picked. You need to use the old-style, C++03 construction:
std::vector<double> bestScores(s, -1.0);
This is one of the gotchas of brace-enclosed initializers. They don't play well for certain standard library container instantiations. You have to remember that the std::initializer_list constructor will trump the others.
The issue is that when a class has an std::initializer_list constructor, it will prefer that when using the uniform initialization syntax if the arguments are convertible to the initializer_list's type (double in this case). See a detailed answer at programmers.stackexchange.com.
For now, your solution is to use the non-uniform syntax that uses parenthesis. This means it won't consider the std::initializer_list constructor, and do what you want in this case.
std::vector<double> bestScores(s, -1.0)

Templates don't always guess initializer list types

#include <initializer_list>
#include <utility>
void foo(std::initializer_list<std::pair<int,int>>) {}
template <class T> void bar(T) {}
int main() {
foo({{0,1}}); //This works
foo({{0,1},{1,2}}); //This works
bar({{0,1}}); //This warns
bar({{0,1},{1,2}}); //This fails
bar(std::initializer_list<std::pair<int,int>>({{0,1},{1,2}})); //This works
}
This doesn't compile in gcc 4.5.3, it gives a warning for the marked line saying deducing ‘T’ as ‘std::initializer_list<std::initializer_list<int> >’ and an error for the marked line saying no matching function for call to ‘bar(<brace-enclosed initializer list>)’. Why can gcc deduce the type of the first call to bar but not the second, and is there a way to fix this other than long and ugly casting?
GCC according to C++11 cannot deduce the type for either first two calls to bar. It warns because it implements an extension to C++11.
The Standard says that when a function argument in a call to a function template is a { ... } and the parameter is not initializer_list<X> (optionally a reference parameter), that then the parameter's type cannot be deduced by the {...}. If the parameter is such a initializer_list<X>, then the elements of the initializer list are deduced independently by comparing against X, and each of the deductions of the elements have to match.
template<typename T>
void f(initializer_list<T>);
int main() {
f({1, 2}); // OK
f({1, {2}}); // OK
f({{1}, {2}}); // NOT OK
f({1, 2.0}); // NOT OK
}
In this example, the first is OK, and the second is OK too because the first element yields type int, and the second element compares {2} against T - this deduction cannot yield a constradiction since it doesn't deduce anything, hence eventually the second call takes T as int. The third cannot deduce T by any element, hence is NOT OK. The last call yields contradicting deductions for two elements.
One way to make this work is to use such a type as parameter type
template <class T> void bar(std::initializer_list<std::initializer_list<T>> x) {
// ...
}
I should note that doing std::initializer_list<U>({...}) is dangerous - better remove those (...) around the braces. In your case it happens to work by accident, but consider
std::initializer_list<int> v({1, 2, 3});
// oops, now 'v' contains dangling pointers - the backing data array is dead!
The reason is that ({1, 2, 3}) calls the copy/move constructor of initializer_list<int> passing it a temporary initializer_list<int> associated with the {1, 2, 3}. That temporary object will then be destroyed and die when the initialization is finished. When that temporary object that is associated with the list dies, the backing-up array holding the data will be destroyed too (if the move is elided, it will live as long as "v"; that's bad, since it would not even behave bad guaranteedly!). By omitting the parens, v is directly associated with the list, and the backing array data is destroyed only when v is destroyed.
List initialization relies on knowing what type is being initialized. {1} could mean many things. When applied to an int, it fills it with a 1. When applied to a std::vector<int>, it means to create a one-element vector, with 1 in the first element. And so on.
When you call a template function who's type is completely unconstrained, then there is no type information for list initialization to work with. And without type information, list initialization cannot work.
For example:
bar({{0,1}});
You expect this to be of the type std::initializer_list<std::pair<int,int>>. But how could the compiler know that? bar's first parameter is an unconstrained template; it can literally be any type. How could the compiler possibly guess that you meant this specific type?
Quite simply, it can't. Compilers are good, but they're not clairvoyant. List initialization can only work in the presence of type information, and unconstrained templates remove all of that.
By all rights, that line should have failed to compile, according to C++11. It cannot deduce what type you intended the {...} to be, so it should have failed. That looks like a GCC bug or something.

Uniform initialization in C++0x, when to use () instead of {}?

Is there a rule of thumb to decide when to use the old syntax () instead of the new syntax {}?
To initialize a struct:
struct myclass
{
myclass(int px, int py) : x(px), y(py) {}
private:
int x, y;
};
...
myclass object{0, 0};
Now in the case of a vector for example, it has many constructors. Whenever I do the following:
vector<double> numbers{10};
I get a vector of 1 element instead of one with 10 elements as one of the constructors is:
explicit vector ( size_type n, const T& value= T(), const Allocator& = Allocator() );
My suspicion is that whenever a class defines an initializer list constructor as in the case of a vector, it gets called with the {} syntax.
So, is what I am thinking correct. i.e. Should I revert to the old syntax only whenever a class defines an initializer list constructor to call a different constructor? e.g. to correct the above code:
vector<double> numbers(10); // 10 elements instead of just one element with value=10
I've found the answer in the standard docs(latest draft). Hopefully, I'll try to explain what I understood.
First, if a class defines an initialization list constructor, then it is used whenever suitable:
§ 8.5.4 (page 203)
Initializer-list constructors are
favored over other constructors in
list-initialization (13.3.1.7).
I think this is a great feature to have, eliminating the headache associated with the non-uniform style :)
Anyway, the only gotcha(which my question is about) is that if you design a class without the initializer constructor, then you add it later you may get surprising result.
Basically, imagine std::vector didn't have the initializer list constructor, then the following would create a vector with 10 elements:
std::vector<int> numbers{10};
By adding the initializer list constructor, the compiler would favor it over the other constructor because of the {} syntax. This behavior would happen because the elements of the init-list {10} are accepted using the init-list constructor. If there is no acceptable conversion, any other constructor shall be used e.g.:
std::vector<string> vec{10};
// a vector of 10 elements.
// the usual constructor got used because "{0}"
// is not accepted as an init-list of type string.
Take a look at this:
http://www.informit.com/guides/content.aspx?g=cplusplus&seqNum=453&rll=1
The use of a {}-style initializers on a variable has no direct mapping to the initialization lists on any constructors of the class. Those constructor initialization lists can be added/removed/modified without breaking existing callers.
Basically the different behavior of the container is special, and requires special code in that container, specifically a constructor taking a std::initializer_list. For POD and simple objects, you can use {} and () interchangeably.