Как инициализировать класс, например std::array

Я пытаюсь написать класс-контейнер для векторной арифметики. Объекты статичны по размеру:

template<typename T, unsigned N>
class vec{
    T data[N] = {0};
public:
    vec(std::initializer_list<T> ini){
        std::copy(ini.begin(), ini.end(), data);
    }
}

Вот как далеко я зашел.

Но затем я протестировал класс std::array для сравнения и заметил, что он каким-то образом мог сделать статическое утверждение, если список инициализаторов был слишком длинным или коротким.

std::array<float, 2> a = {1, 2, 3, 4} <- instant error message from the visual studio ide

В моем классе мне пришлось бы проверять длину списка инициализаторов во время выполнения.

Я предполагаю, что классу std::array каким-то образом удается напрямую инициализировать данные с помощью нотации списка инициализаторов без класса std::initializer_list.

Можно ли инициализировать мой класс так же, как std::array?


person bakkaa    schedule 15.09.2015    source источник
comment
Одна из причин, по которой ваш vec не позволит этого, заключается в том, что T data[n] является частным... сделайте его общедоступным, а затем избавьтесь от конструктора. Кроме того, ваша примерная строка для std::array выше компилируется, если вы включаете закрытие ;   -  person JVene    schedule 15.09.2015


Ответы (1)


std::array является агрегатом, поэтому он использует агрегатная инициализация. Предоставление избыточных элементов во время инициализации агрегата является некорректным и требует диагностики. Компилятор как минимум должен выдать предупреждение, и gcc, и clang делают это ошибкой. Поэтому, если вы сделаете свой класс агрегатом, вы можете заставить его работать так же, как std::array. Обратите внимание: в инициализаторах членов класса ваш класс не является агрегатным в C++11, но не в C++14.

Мы можем увидеть, что это совокупность, перейдя к черновому стандартному разделу C++11 23.3.2.1 [array.overview]:

Массив — это совокупность (8.5.1), которую можно инициализировать с помощью синтаксиса

array<T, N> a = { initializer-list };

где список-инициализаторов — это разделенный запятыми список до N элементов, типы которых могут быть преобразованы в T.

а раздел 8.5.1 [dcl.init.aggr] описывает агрегированную инициализацию и говорит:

Список-инициализаторов сформирован неправильно, если количество предложений-инициализаторов превышает количество членов или элементов для инициализации.

Проект стандарта предоставляет для изложения возможную реализацию, которая в сокращенном до минимума виде выглядит следующим образом:

template <class T, size_t N>
struct array {
    T elems[N];
};

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

Элементы переменных-членов показаны только для демонстрации, чтобы подчеркнуть, что массив является агрегатом класса. Элементы имени не являются частью интерфейса массива

который является агрегатом и будет выдавать ошибку как с gcc, так и с clang, если предоставлены лишние элементы.

Также см. Что такое агрегаты и POD и чем/почему они особенны?.

person Shafik Yaghmour    schedule 15.09.2015