3

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";
}

Live

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?

Live

7
  • 1
    {{}} is not an empty list. It explicitly has 1 element. Why would you want to treat it as empty? What about other 1 element lists, should they also be treated as empty? Your question doesn't make sense to me. Commented Sep 11, 2023 at 11:34
  • 3
    In your initialisation, saying {{}} is like saying {double{}} which is like saying {double{0.}} which is like saying {0.}. You could also pass two values: {{},{}}. Commented Sep 11, 2023 at 11:51
  • 1
    By providing a constructor that takes an initializer_list, you make list initialization special (i.e., the prefered way to initialize the object). Just remove that constructor, and the list initialization falls back to aggregate initialization, and suddenly the inner braces now initialize the first member with an empty list, just what you want. Commented Sep 11, 2023 at 12:06
  • 1
    @JesperJuhl: I suspect OP expects {{}} to be Wrap{std::initializer_list<double>{}} and not Wrapper{std::initializer_list<double>{double{}}}}. Commented Sep 11, 2023 at 12:49
  • @Jarod42 indeed and I understand that I may be wrong on this point. I know that initialization rules are confusing as they may depend on the exact context. Thus my question as I suspect that my library users my have the same (mis)understanding. Commented Sep 11, 2023 at 17:21

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.