Brace Initialization: A Mess¶
Explicit Constructor And Brace Initialization¶
Any explicit constructor can be invoked the “new” brace initialization syntax
… unless there is a
std::initializer_list
constructor
#include <gtest/gtest.h>
struct point
{
point(int x, int y) // <--- explicit ctor, 2 parameters
: x{x}, y{y} {}
int x;
int y;
};
TEST(brace_initialization_suite, basic)
{
point p1(1,2); // <--- explicitly using explicit ctor
point p2{3,4}; // <--- implicitly using explicit ctor (no initializer_list ctor found)
ASSERT_EQ(p1.x, 1);
ASSERT_EQ(p1.y, 2);
ASSERT_EQ(p2.x, 3);
ASSERT_EQ(p2.y, 4);
}
Ambiguity: Explicit And std::initializer_list
Constructor¶
What if there are two constructors which would satisfy calling sequence?
⟶ be explicit
#include <gtest/gtest.h>
class point
{
public:
point(int x, int y)
: x{x}, y{y} {}
int x;
int y;
};
struct pointcloud
{
pointcloud(point p1, point p2) // <--- explicit ctor
{
points.push_back(p1);
points.push_back(p2);
explicit_ctor_called = true;
initlist_ctor_called = false;
}
pointcloud(std::initializer_list<point> points) // <--- initializer_list ctor
: points(points)
{
explicit_ctor_called = false;
initlist_ctor_called = true;
}
std::vector<point> points;
bool initlist_ctor_called;
bool explicit_ctor_called;
};
TEST(brace_initialization_suite, explicit_ctor)
{
point p1{1,2};
point p2{3,4};
pointcloud cloud(p1, p2); // <--- using explicit ctor
ASSERT_TRUE(cloud.explicit_ctor_called);
ASSERT_EQ(cloud.points.size(), 2);
}
TEST(brace_initialization_suite, initlist_ctor)
{
point p1{1,2};
point p2{3,4};
pointcloud cloud{p1, p2}; // <--- initializer_list ctor
ASSERT_EQ(cloud.points.size(), 2);
ASSERT_TRUE(cloud.initlist_ctor_called);
}
Rule¶
Use brace initialization, preferably
Unless something does not work or compile 🐷
Realistic Example: std::vector
: Two int
(Explicit)¶
std::vector<int>
has one explicit constructors which takes twoint
parametersOne is the number of elements to create, one is their value
Using the explicit constructor, explicitly, by writing gool old function-call-style initialization
#include <vector>
#include <iostream>
int main()
{
std::vector<int> ints(3, 42);
for (int i: ints) std::cout << i << '\n';
return 0;
}
$ ./code/c++11-brace-initialization-vector-explicit
42
42
42
Realistic Example: std::vector
: Two int
(std::initializer_list
)¶
std::vector<int>
has one another constructor which takes astd::initializer_list<int>
… of arbitrary size - even 2 is ok
⟶ must use brace initialization to disabiguate
#include <vector>
#include <iostream>
int main()
{
std::vector<int> ints{3, 42};
for (int i: ints) std::cout << i << '\n';
return 0;
}
$ ./code/c++11-brace-initialization-vector-initializer-list
3
42