Is there a difference between using curly braces or the assignment operator while defining an array in C++11?
std::array<int, 2> a{1, 2}
// or
std::array<int, 2> b{{1, 2}}
and
std::array<int, 2> = a{1, 2}
Related
This code used to compile with earlier g++ versions, e.g. 5.3.
Using 10.2 I'm getting the following (using compiler option -std=c++11)
tmp1.cpp: In function ΓÇÿint main(int, char**)ΓÇÖ:
tmp1.cpp:17:117: error: modification of ΓÇÿ<temporary>ΓÇÖ is not a constant expression
17 | static constexpr std::initializer_list<std::pair<int, std::initializer_list<int> > > s={{0, {1}}, {1, {2}}, {2, {3}}};
| ^
tmp1.cpp:18:33: error: non-constant condition for static assertion
18 | static_assert(isSortedPairVector(s.begin(), s.end()), "sorted");
| ~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~
I think this has something to do with an initializer_list containing another initializer_list -- as with
std::initializer_list<std::pair<int, int> >
everything is fine.
Here is the code:
#include <initializer_list>
#include <utility>
#include <iostream>
template<typename T>
constexpr bool isSortedPairVector(const T&_p, const T&_pEnd)
{ return _p == _pEnd || _p + 1 == _pEnd
? true
: _p->first < (_p + 1)->first
&& isSortedPairVector(_p + 1, _pEnd);
}
int main(int, char**)
{
static constexpr std::initializer_list<std::pair<int, std::initializer_list<int> > > s={{0, {1}}, {1, {2}}, {2, {3}}};
static_assert(isSortedPairVector(s.begin(), s.end()), "sorted");
}
Curiously -- making the contained initializer_list empty makes the code compileable. e.g.
static constexpr std::initializer_list<std::pair<int, std::initializer_list<int> > > s={{0, {}}, {1, {}}, {2, {}}};
The solution to this problem is to make every std::initializer_list object used inside another std::initializer_list a constexpr variable.
Thus the following compiles:
static constexpr std::initializer_list<int> s1({1, 2});
static constexpr std::initializer_list<
std::pair<int, std::initializer_list<int> >
> s={
{0, s1},
{1, s1},
{2, s1}
};
I do not understand why this works fine:
std::array<double, 2> someArray = {0,1};
std::shared_ptr<MyClass> myobj = std::make_shared<MyClass>(someArray);
But this does not work:
std::shared_ptr<MyClass> myobj = std::make_shared<MyClass>({0,1});
Compiler says:
too many arguments to function ‘std::shared_ptr< _Tp> std::make_shared(_Args&& ...)
...
candidate expects 1 argument, 0 provided
Question: Can someone clarify why this happens and if there is any way I can fix the second approach without defining an extra variable?
Edit:
Example of MyClass:
#include <memory> //For std::shared_ptr
#include <array>
#include <iostream>
class MyClass{
public:
MyClass(std::array<double, 2> ){
std::cout << "hi" << std::endl;
};
};
Braced initializers {} can never be deduced to a type (in a template context). A special case is auto, where it is deduced to std::initializer_list. You always have to explictly define the type.
auto myobj = std::make_shared<MyClass>(std::array<double, 2>{0, 1});
The type of {0, 0} is context-dependent. If {0, 0} is being used to immediately construct another object of known type, then it represents a prvalue of that object type:
MyClass m({0, 0});
Here, {0, 0} refers to a prvalue of type std::array<double, 2>
On the other hand, if there are no constraints on the type, then {0, 0} refers to an initializer list of type std::initializer_list<int>:
auto vals = {0, 0};
There's no way to initialize MyClass from std::initializer_list<int>, so make_shared fails to compile:
MyClass m(vals); // Fails: can't construct MyClass from initializer list
How does this connect to std::make_shared? Because std::make_shared is a template, {0, 0} isn't being used to construct a specific type. As a result, it's treated as a std::initializer_list.
I have struct which contains array of inner struct. I want to use method emplace_back() of vector<my_struct>. But I cannot figure how could I initialize this struct correctly:
struct my_struct
{
struct
{
float x, y, z;
} point[3];
};
std::vector<my_struct> v;
v.emplace_back(
{0, 0, 0},
{0, 0, 0},
{0, 0, 0}
);
This gives compilation error error: no matching function for call to ‘std::vector<main()::my_struct>::emplace_back(<brace-enclosed initializer list>, <brace-enclosed initializer list>, <brace-enclosed initializer list>)
Is it possible to emplace_back this struct (I'm using C++17)? Should I write custom constructor?
how about this:
v.push_back(my_struct{{{0, 1, 2}, {3, 4, 5}, {6, 7, 8}}});
Since C++11, it is possible to initialize member variables in class definitions:
class Foo {
int i = 3;
}
I know I can initialize an std::array like this:
std::array<float, 3> phis = {1, 2, 3};
How can I do this in a class definition? The following code gives an error:
class Foo {
std::array<float, 3> phis = {1, 2, 3};
}
GCC 4.9.1:
error: array must be initialized with a brace-enclosed initializer
std::array<float, 3> phis = {1, 2, 3};
^ error: too many initializers for 'std::array<float, 3ul>'
You need one more set of braces, which is non-intuitive.
std::array<float, 3> phis = {{1, 2, 3}};
I'm wondering whether the tuple can be initialized by initializer list (to be more precise - by initializer_list of initializer_lists)? Considering the tuple definition:
typedef std::tuple< std::array<short, 3>,
std::array<float, 2>,
std::array<unsigned char, 4>,
std::array<unsigned char, 4> > vertex;
is there any way of doing the following:
static vertex const nullvertex = { {{0, 0, 0}},
{{0.0, 0.0}},
{{0, 0, 0, 0}},
{{0, 0, 0, 0}} };
I just want to achieve same functionality I got using struct instead of tuple (thus only arrays are initialized by initializer_list):
static struct vertex {
std::array<short, 3> m_vertex_coords;
std::array<float, 2> m_texture_coords;
std::array<unsigned char, 4> m_color_1;
std::array<unsigned char, 4> m_color_2;
} const nullvertex = {
{{0, 0, 0}},
{{0.0, 0.0}},
{{0, 0, 0, 0}},
{{0, 0, 0, 0}}
};
There is no reason I must use tuples, just wondering. I'm asking, because I'm unable to go through g++ templates errors which are generated by my attempt of such tuple initialization.
#Motti: So I missed the proper syntax for uniform initialization -
static vertex const nullvertex = vertex{ {{0, 0, 0}},
{{0.0, 0.0}},
{{0, 0, 0, 0}},
{{0, 0, 0, 0}} };
and
static vertex const nullvertex{ {{0, 0, 0}},
{{0.0, 0.0}},
{{0, 0, 0, 0}},
{{0, 0, 0, 0}} };
But it seems that all the trouble lies in arrays, which got no constructor for initializer_list and wrapping arrays with proper constructor seems not so easy task.
Initializer lists aren't relevant for tuples.
I think that you're confusing two different uses of curly braces in C++0x.
initializer_list<T> is a homogeneous collection (all members must be of the same type, so not relevant for std::tuple)
Uniform initialization is where curly brackets are used in order to construct all kinds of objects; arrays, PODs and classes with constructors. Which also has the benefit of solving the most vexing parse)
Here's a simplified version:
std::tuple<int, char> t = { 1, '1' };
// error: converting to 'std::tuple<int, char>' from initializer list would use
// explicit constructor 'std::tuple<_T1, _T2>::tuple(_U1&&, _U2&&)
// [with _U1 = int, _U2 = char, _T1 = int, _T2 = char]'
std::tuple<int, char> t { 1, '1' }; // note no assignment
// OK, but not an initializer list, uniform initialization
The error message says is that you're trying to implicitly call the constructor but it's an explicit constructor so you can't.
Basically what you're trying to do is something like this:
struct A {
explicit A(int) {}
};
A a0 = 3;
// Error: conversion from 'int' to non-scalar type 'A' requested
A a1 = {3};
// Error: converting to 'const A' from initializer list would use
// explicit constructor 'A::A(int)'
A a2(3); // OK C++98 style
A a3{3}; // OK C++0x Uniform initialization