63

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.

erjot
  • 1,362
  • 1
  • 9
  • 13

1 Answers1

71

Initializer lists aren't relevant for tuples.

I think that you're confusing two different uses of curly braces in C++0x.

  1. initializer_list<T> is a homogeneous collection (all members must be of the same type, so not relevant for std::tuple)
  2. 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
Motti
  • 110,860
  • 49
  • 189
  • 262
  • 13
    Why is constructing a `std::tuple` with a braced init list a bad thing? It works for `std::pair`s, and a `std::tuple` is the `std::pair`'s generalization, so I don't understand the reason for this limitation :S... – rubenvb Aug 28 '12 at 19:36
  • 6
    @rubenvb it's OK to initialize a `tuple` with uniform initialization (braces) but to do so you must drop the equals sign. If you have an equals sign it means that you construct a temporary with the one parameter constructor accepting an initialization list and then use the copy constructor from the temporary value (although the compiler can elide some of this). – Motti Aug 29 '12 at 07:50
  • 5
    that is some really bad comment answer to @rubenvb... no temporary will be introduced. that the respective constructor is explicit is just a big shame – Johannes Schaub - litb Aug 29 '12 at 07:59
  • 1
    @JohannesSchaub-litb, correct me if I'm mistaken but when you write `T t = x;` it requires that `T` have an accessible implicit constructor that accepts `x` and has an accessible copy constructor. Once it's determined that `t` could be constructed from a temporary `T` the compiler can elide the temporary, otherwise it should not compile. – Motti Aug 29 '12 at 11:41
  • I think the simplified version `std::tuple t = { 1, '1' }; ` is bad because `std::tuple t = { (int)1, (char)'1' }; ` still generates the same error. As [this](http://stackoverflow.com/questions/26947704/implicit-conversion-failure-from-initializer-list) explained, the error message is generated here because tuple does not have constructor that accepts initializer_list as [tuple constructor](http://www.cplusplus.com/reference/tuple/tuple/tuple/), – writalnaie Mar 08 '15 at 07:22