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.
Related
I've been going through 'A Tour of C++' and Bjarne uses the the c++11 initializer list feature in member initialization in a constructor, like so (using curly brackets):
A a;
B b;
Foo(Bar bar):
a{bar.a}, b{bar.b}
{}
This, however doesn't compile prior to c++11. What is the difference with the old member initializer list (using round brackets):
Foo(Bar bar):
a(bar.a), b(bar.b)
{}
So what is the difference and when should one be preferred over the other?
So what is the difference?
Round brackets only work for non-class types, or types with a suitable constructor for the number of arguments in the brackets.
Squiggly braces work for these, and also for aggregates - simple struct or array types with no constructor. So the following will work:
struct {
int a,b;
} aggregate;
int array[2];
Foo() : aggregate{1,2}, array{3,4} {}
Finally, braces will match a constructor taking a suitably-typed initializer_list, rather than a constructor with parameter(s) to match the arguments. For example:
std::vector<int> v1;
std::vector<int> v2;
Foo() :
v1(10,2), // 10 elements with value 2
v2{10,2} // 2 elements with value 10,2
{}
when should one be preferred over the other?
Prefer round brackets if you want to make it clearer that the initialisation is using a constructor rather than aggregate or initializer_list; or to force use of a specific constructor.
Prefer braces when you need a form of initialisation not otherwise supported; or when you just want the initialisation to "do the right thing".
In the cases where both do the same thing, the choice is largely aesthetic.
There can be a difference in a few really annoying edge cases:
std::vector<int> v{3, 2}; // constructs a vector containing [3, 2]
std::vector<int> u(3, 2); // constructs a vector containing [2, 2, 2]
That is true regardless of whether v and u are just variables in a function or are members of a class initialized in an initialization list.
But outside the cases where a std::initializer_list<T> constructor overlaps with a normal constructor taking the same number of arguments, there is no difference.
The short description is: the notation in the member initializer list matches that of variables initialized elsewhere. Sadly, the description of what it does is not as easy at all because there are two somewhat conflicting changes relating to the use of curly braces for constructor calls:
The unified initialization syntax was intended to make to make have all constructions use curly braces and it would just call the corresponding constructor, even if it is the default argument or the type doesn't have a constructor at all and direct initialization is used.
To support variable number of arguments, curly braces can be used to provide an std::initializer_list<T> without an extra pair of parenthesis/curly braces. If there is a constructor taking an std::initializer_list<T> (for a suitable type T) this constructor is used when using curly braces.
Put differently, if there is no std::initializer_list<T> constructor but some other user defined constructor the use of parenthesis and curly braces is equivalent. Otherwise it calls the std::initializer_list<T> constructor. ... and I guess, I'm missing a few details as the entire initialization is actually quite complicated.
I've been going through 'A Tour of C++' and Bjarne uses the the c++11 initializer list feature in member initialization in a constructor, like so (using curly brackets):
A a;
B b;
Foo(Bar bar):
a{bar.a}, b{bar.b}
{}
This, however doesn't compile prior to c++11. What is the difference with the old member initializer list (using round brackets):
Foo(Bar bar):
a(bar.a), b(bar.b)
{}
So what is the difference and when should one be preferred over the other?
So what is the difference?
Round brackets only work for non-class types, or types with a suitable constructor for the number of arguments in the brackets.
Squiggly braces work for these, and also for aggregates - simple struct or array types with no constructor. So the following will work:
struct {
int a,b;
} aggregate;
int array[2];
Foo() : aggregate{1,2}, array{3,4} {}
Finally, braces will match a constructor taking a suitably-typed initializer_list, rather than a constructor with parameter(s) to match the arguments. For example:
std::vector<int> v1;
std::vector<int> v2;
Foo() :
v1(10,2), // 10 elements with value 2
v2{10,2} // 2 elements with value 10,2
{}
when should one be preferred over the other?
Prefer round brackets if you want to make it clearer that the initialisation is using a constructor rather than aggregate or initializer_list; or to force use of a specific constructor.
Prefer braces when you need a form of initialisation not otherwise supported; or when you just want the initialisation to "do the right thing".
In the cases where both do the same thing, the choice is largely aesthetic.
There can be a difference in a few really annoying edge cases:
std::vector<int> v{3, 2}; // constructs a vector containing [3, 2]
std::vector<int> u(3, 2); // constructs a vector containing [2, 2, 2]
That is true regardless of whether v and u are just variables in a function or are members of a class initialized in an initialization list.
But outside the cases where a std::initializer_list<T> constructor overlaps with a normal constructor taking the same number of arguments, there is no difference.
The short description is: the notation in the member initializer list matches that of variables initialized elsewhere. Sadly, the description of what it does is not as easy at all because there are two somewhat conflicting changes relating to the use of curly braces for constructor calls:
The unified initialization syntax was intended to make to make have all constructions use curly braces and it would just call the corresponding constructor, even if it is the default argument or the type doesn't have a constructor at all and direct initialization is used.
To support variable number of arguments, curly braces can be used to provide an std::initializer_list<T> without an extra pair of parenthesis/curly braces. If there is a constructor taking an std::initializer_list<T> (for a suitable type T) this constructor is used when using curly braces.
Put differently, if there is no std::initializer_list<T> constructor but some other user defined constructor the use of parenthesis and curly braces is equivalent. Otherwise it calls the std::initializer_list<T> constructor. ... and I guess, I'm missing a few details as the entire initialization is actually quite complicated.
struct S
{
int x;
int y;
};
std::atomic<S> asd{{1, 2}}; // what should this be? This doesn't work
Edit: Both {{1, 2}} and ({1, 2}) work in g++, neither work in clang. Is there a workaround for clang?
This is clang bug 18097. Here's a long thread discussing the issue, which seems to be that clang only supports scalar types for T in atomic<T>. The C++11 standard clearly states (ยง29.5/1) that T can be any trivially copyable type.
Both the usages shown in the question should match this constructor
constexpr atomic(T) noexcept;
The only way I can think of working around this is to default construct atomic<S> and then use atomic::store to initialize the object.
std::atomic<S> asd;
asd.store({1,2});
std::atomic<S> asd({1, 2});
std::atomic<S> has a constructor which takes a value of type S.
The initializer list {1, 2} is implicitly converted to a temporary S because of this constructor.
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>.
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)