Wrong std::vector constructor - c++

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)

Related

constructor with variadic multidimensional initializer_list

I have the following constructor:
class A {
template<class ...T>
A(std::initializer_list<T> && ... args);
}
And I have the code for that class:
A a1 = {{5.0f, 6.0f}, {-7.0f, 8.0f}};
A a2 = {{{5.0f, 3.f}, {6.0f, 7.f}}, {{-7.0f, 9.f}, {12.f, 8.0f}}};
a1 can be compiled and a2 can't be compiled. I understand, curly braces are only syntax sugar and not making the type by default, only when passing it to function with arguments that can be initilized with initilizer_list (e.g. std::initializer_list<float> in case of A and variable a1).
I wonder, is there any workaround that can help passing any dimensional std::initializer_list<std::initializer_list<std::initializer_list<...>...>...> to function/constructor?
I checked documentation and tried several different hacks but it will not work.
So, basic answer would be it is not possible.
It is not possible to make constructor or any other function accepting brace list of undefined number of brace lists because brace list has no type and cannot be implicitly converted to std::initilizer_list<...>.
std::initializer_list...>...> , the form
must have partial specialization , and then please reference to :
The program is ill-formed if an explicit or partial specialization of std::initializer_list is declared.
(since C++17)
https://en.cppreference.com/w/cpp/utility/initializer_list

Initialize an std::array of tuples with curly braces

This probably has a very simple answer, but I really can't figure it out. Why do I get errors for doing this? What's the correct way to initialize something like this?
std::array<std::tuple<int, std::string>, 3> tuples{
{3, "a"},
{7, "b"},
{2, "c"}
};
On MSVC 2015, I get the following errors:
No suitable constructor exists to convert from "int" to "std::tuple<int, std::string>"
No suitable constructor exists to convert from "const char[2]" to "std::tuple<int, std::string>"
This is an outstanding issue with tuple. See, its constructor in C++11/14 is explicit. And therefore, it cannot participate in copy-list-initialization, which is what the inner braced-init-lists do (the outer ones are direct-list-initialization).
The idea was to prevent you from being able to bypass a class's explicit constructors through tuple. But, in C++17, this will be changed: if all of the tuple's types themselves are implicitly convertible from the respective given type, then so too will that constructor of tuple.
For your specific use case, you could use std::pair. Its constructor is never explicit.

Emplacement of a vector with initializer list

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>.

How generic is the {} construction syntax?

In a talk about initialization lists, I understood Stroustrup basically saying that the new construction syntax with curly braces is supposed to be a general replacement for all the previous construction syntaxes:
X x1(); // most vexing parse ... doesn't work as intended
X x2(x1);
X x3 = x1;
X x4 = X();
Instead, the new syntax is supposed to be used uniformly as a possible replacement that you can use in every situation ... again, that's the core message that I took from his talk. Maybe I misunderstood him.
So, the question is, how generic is this syntax? Is it possible to never use old-style construction in new C++11 code or are there situations where you have to revert?
This question was triggered/motivated when I encountered the following error, which I believe is an error in the compiler (but I'd be happy to be corrected).
struct X {};
int main() {
X x;
X& y{x}; // works with (x)
X& z{y}; // works with (y)
}
Which doesn't compile on g++ 4.7.1 nor does it on ideone's 4.5.1.
prog.cpp: In function 'int main()':
prog.cpp:5:9: error: invalid initialization of non-const reference of type 'X&' from an rvalue of type '<brace-enclosed initializer list>'
prog.cpp:6:9: error: invalid initialization of non-const reference of type 'X&' from an rvalue of type '<brace-enclosed initializer list>'
Note that it works when I replace X with int.
Brace initialization works everywhere an initializer is used. There are situations where you have to use parens in order to access a constructor that a brace initializer cannot access, but they are rare.
std::vector<int> v(1,1);
std::vector<int> v{1,1};
vector<int> happens to have a specialized constructor that takes two ints and is therefore ambiguous with trying to construct a vector two ints long. The ambiguous constructor exists only for backwards compatibility. New classes should not be defined with any constructors that would conflict with an initializer_list.
The ambiguity is resolved by the fact that brace initialization syntax prefers initializer_list constructors over other constructors that would otherwise match. If you want to resolve the ambiguity in favor of using the non-initializer_list constructor then you can't use brace initialization.
Bjarne Stroustrup writes
The uniform use of {} initialization only became possible in C++11, so older C++ code uses () and = initialization. Consequently, the () and = may be more familiar to you. However, I don't know any logical reason to prefer the () notation except in the rare case where you need to distinguish between initialization with a list of elements and a list of constructor arguments.
— The C++ Programming Language, Fourth Edition §17.3.2.1
Your example code is perfectly legal and should work as expected. The error you're getting is simply a bug in GCC. Clang and VC++ 2012 both accept the code.

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.