I've got a class that basically contains a std::vector.
I can default-construct an object of this class, leaving the contained std::vector empty.
I can also value-construct it from a set of values, given through a braced-initializers list.
I'd like to have a consistent behavior between both forms,per se, passing an empty list should give an empty std::vector.
Yet I cannot reproduce the expected behavior, as the empty list actually construct a single default element list:
#include <iostream>
#include <vector>
struct Wrap {
std::vector<double> v;
Wrap() = default;
Wrap(std::initializer_list<double> const &l) : v(l) {}
};
int main() {
Wrap v0 = {};
std::cout << v0.v.size() << "; expected 0\n";
Wrap v1 = {{}};
// expecting 0, getting 1
std::cout << v1.v.size() << "; expected 0\n";
}
From Why does double empty curly braces { { } } create a std::initializer_list with one element, not zero? I get that it is the expected behaviour of std::initializer_list so how can I redesign my class in order to have:
- default construction giving empty vector;
- braced-initializers list of value giving also an empty vector if list is empty?
NB I thought about template construction from T const (&)[N] yet I was interested in taking benefit from no-narrowing conversion enforced by std::initializer_list.
[EDIT] here is an extended example that shows how brace initialization rules confuse me (and possibily my libraries client)
#include <iostream>
#include <vector>
struct Wrap {
std::vector<double> v;
Wrap() { std::cout << "default constructor\n"; }
Wrap(std::initializer_list<double> const &l) : v(l) {
std::cout << "IL constructor\n";
}
};
int main() {
{
Wrap v = {1, 2};
std::cout << v.v.size() << "; expected 2\n";
}
{
Wrap v = {{1, 2}};
std::cout << v.v.size() << "; expected 2, braces elision?\n";
}
{
Wrap v = {1};
std::cout << v.v.size() << "; expected 1\n";
}
{
Wrap v = {{1}};
std::cout << v.v.size() << "; expected 1, braces elision?\n";
}
{
Wrap v = {};
std::cout << v.v.size()
<< "; expected 0, default ctor has precedence other IL one\n";
}
{
Wrap v = {{}};
std::cout << v.v.size() << "; expected 0, braces elision?\n";
}
}
And the obtained output:
Program returned: 0
IL constructor
2; expected 2
IL constructor
2; expected 2, braces elision?
IL constructor
1; expected 1
IL constructor
1; expected 1, braces elision?
default constructor
0; expected 0, default ctor has precedence other IL one
IL constructor
1; expected 0, braces elision?