Инициализация std::tuple из списка инициализаторов

Меня интересует, можно ли инициализировать кортеж списком инициализаторов (точнее - списком инициализаторов_списков_инициализаторов)? Учитывая определение кортежа:

typedef std::tuple< std::array<short, 3>,
                    std::array<float, 2>,
                    std::array<unsigned char, 4>,
                    std::array<unsigned char, 4> > vertex;

есть ли способ сделать следующее:

static vertex const nullvertex = { {{0, 0, 0}},
                                   {{0.0, 0.0}},
                                   {{0, 0, 0, 0}},
                                   {{0, 0, 0, 0}} };

Я просто хочу добиться той же функциональности, которую я получил, используя struct вместо tuple (таким образом, инициализатором_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}}
};

Нет причин, по которым я должен использовать кортежи, просто интересно. Я спрашиваю, потому что я не могу пройти через ошибки шаблонов g++, которые генерируются моей попыткой инициализации такого кортежа.

@Motti: Итак, я пропустил правильный синтаксис для универсальной инициализации -

static vertex const nullvertex = vertex{ {{0, 0, 0}},
                                         {{0.0, 0.0}},
                                         {{0, 0, 0, 0}},
                                         {{0, 0, 0, 0}} };

и

static vertex const nullvertex{ {{0, 0, 0}},
                                {{0.0, 0.0}},
                                {{0, 0, 0, 0}},
                                {{0, 0, 0, 0}} };

Но, похоже, вся беда кроется в массивах, у которых нет конструктора для initializer_list и обертывание массивов соответствующим конструктором кажется не такой уж простой задачей.


person erjot    schedule 05.08.2010    source источник


Ответы (1)


Списки инициализаторов не относятся к кортежам.

Я думаю, что вы путаете два разных использования фигурных скобок в С++ 0x.

  1. initializer_list<T> — это однородная коллекция (все элементы должны быть одного типа, так что не актуально для std::tuple)
  2. Унифицированная инициализация — это место, где фигурные скобки используются для построения всех видов объекты; массивы, POD и классы с конструкторами. Что также имеет преимущество решения самого неприятного синтаксического анализа)

Вот упрощенная версия:

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

В сообщении об ошибке говорится, что вы пытаетесь неявно вызвать конструктор, но это явный конструктор, поэтому вы не можете.

В основном то, что вы пытаетесь сделать, выглядит примерно так:

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
person Motti    schedule 05.08.2010
comment
Почему построение std::tuple со списком инициализации в фигурных скобках — это плохо? Это работает для std::pairs, а std::tuple является обобщением std::pair, поэтому я не понимаю причину этого ограничения: S... - person rubenvb; 28.08.2012
comment
@rubenvb можно инициализировать tuple с помощью унифицированной инициализации (скобки), но для этого вы должны отбросить знак равенства. Если у вас есть знак равенства, это означает, что вы создаете временный объект с одним конструктором параметров, принимающим список инициализации, а затем используете конструктор копирования из временного значения (хотя компилятор может исключить некоторые из них). - person Motti; 29.08.2012
comment
это какой-то действительно плохой ответ на комментарий к @rubenvb... временный не будет введен. то, что соответствующий конструктор является явным, просто большой позор - person Johannes Schaub - litb; 29.08.2012
comment
@JohannesSchaub-litb, поправьте меня, если я ошибаюсь, но когда вы пишете T t = x;, требуется, чтобы T имел доступный неявный конструктор, который принимает x и имеет доступный конструктор копирования. Как только будет определено, что t может быть создано из временного T, компилятор может пропустить временное, иначе он не должен компилироваться. - person Motti; 29.08.2012
comment
Я думаю, что упрощенная версия std::tuple<int, char> t = { 1, '1' }; плоха, потому что std::tuple<int, char> t = { (int)1, (char)'1' }; по-прежнему выдает ту же ошибку. Как объясняется это, здесь генерируется сообщение об ошибке, поскольку у кортежа нет конструктора который принимает initializer_list как конструктор кортежей, - person writalnaie; 08.03.2015