3

My question is about the lack of conversions between std::initializer_list types where the contained type is more or less cv qualified when those conversions appear to be easily doable.

Consider the following code which is invalid:

std::initializer_list<int> x{1,2,3,4,5,6};
std::initializer_list<int const> y = x; // error! cannot convert!

Now consider std::optional and ignore the ridiculous types:

std::optional<std::vector<int>> x{std::in_place, {1,2,3,4,5}}; // OK
std::optional<std::vector<int const>> y{std::in_place, {1,2,3,4,5}}; // error!

I assume the language spec requires deducing non cv qualified U's for std::initializer_list<U> by default.

As far as I can tell, the whole point of std::optional (and std::any and std::variant) having std::initializer_list constructor overloads is to avoid specifying the exact type of the initializer list. To get the second line of the above code to compile, that's exactly what you must do.

std::initializer_list already holds a const* to it's data (in libc++ anyhow). There's no reason I can see for the above code not to work? Is this a solvable issue in the language, or am I missing something?

xcvr
  • 939
  • 8
  • 15
  • 3
    It's kind of hard to "ignore the ridiculous types", when `vector` is explicitly *not legal* in C++. So why exactly would you expect `initializer_list` to work? What would you be initializing with it? – Nicol Bolas Jan 10 '17 at 03:30
  • To be honest, I don't know. I was writing a generic wrapper type when I discovered this. – xcvr Jan 10 '17 at 03:40
  • Perhaps it would make sense for some type similar to `dynarray`. – xcvr Jan 10 '17 at 03:56
  • @NicolBolas based on [this thread](http://stackoverflow.com/questions/6954906/does-c11-allow-vectorconst-t) I would say that `vector` is *accidentally* not legal, and it might become legal in C++17, not through intent but as a by-product of other changes – M.M Jan 10 '17 at 04:03
  • @M.M It's hardly accidental when the allocator requirements table bans it outright. – T.C. Jan 10 '17 at 05:07
  • @T.C. I mean, when designing the allocator requirements was it part of the rationale that `vector` not be allowed? The discussion on that thread suggests not. – M.M Jan 10 '17 at 05:09
  • Though interesting, the thrust of my question had little to do with `std::vector`. – xcvr Jan 10 '17 at 06:21

1 Answers1

4

It sounds like your question is why std::initializer_list<T const> cannot be constructed from std::initializer_list<T> despite the fact that it would be easy to implement such a conversion.

I think the answer is that you are not supposed to have std::initializer_list<T const> in the first place, given that, as you noted, std::initializer_list<T> only gives const access to its elements anyway.

It might therefore be said that there is a "cultural norm" in C++ that you are not supposed to have any constructors that require a std::initializer_list<T const> argument. None of the standard library containers do, for instance, since a cv-qualified value type is illegal anyway (except in the case of std::array, which, of course, has no user-defined constructors anyway).

If you write your own type MyContainer that supports MyContainer<T const>, then I suggest that you make it look like the following:

template <class T>
class MyContainer {
  public:
    MyContainer(std::initializer_list<std::remove_cv_t<T>> il);
    // ...
};
Brian Bi
  • 111,498
  • 10
  • 176
  • 312
  • "Cultural norm" seems correct! I'll leave this open in case someone (you?) can explain why all initializer lists aren't deduced to be `std::initializer_list` if they have the same semantics as a `std::initializer_list`. – xcvr Jan 10 '17 at 04:06
  • 1
    @xcvr because the template argument of `std::initializer_list` is deduced using the usual rules of template argument deduction, which will never deduce a cv-qualified type, a reference type, an array type, or a function type. – Brian Bi Jan 10 '17 at 04:29
  • Though I think the usual rules of template argument deduction are out the window when the type cannot be deduced unless it is specified as `std::initializer_list`. – xcvr Jan 10 '17 at 04:43