Заключенный в скобки конструктор списка инициализаторов - PullRequest
41 голосов
/ 07 ноября 2010

У меня есть класс Phenotype со следующим конструктором:

Phenotype(uint8 init[NUM_ITEMS]);

Я могу создать такой фенотип:

uint8 data[] = {0,0,0,0,0};
Phenotype p(data);

Но я получаю ошибку, когда пытаюсь создать такой, какthis:

Phenotype p = {0,0,0,0,0};

Вывод:

$ make
g++ -Wall -g main.cpp -std=c++0x
main.cpp: In function ‘int main(int, char**)’:
main.cpp:109: error: no matching function for call to ‘Phenotype::Phenotype(<brace-enclosed initializer list>)’
main.cpp:37: note: candidates are: Phenotype::Phenotype(uint8*)

Кажется, ошибка указывает на то, что существует способ определения конструктора, который принимает заключенный в скобки список инициализатора.Кто-нибудь знает, как это можно сделать?

Ответы [ 3 ]

67 голосов
/ 07 ноября 2010

Это может быть сделано только для агрегатов (массивов и определенных классов. Вопреки распространенному мнению, это работает и для многих неподов). Написание конструктора, который их принимает, невозможно.

Поскольку вы пометили его как "C ++ 0x", то это возможно. Волшебные слова это "Конструктор списка инициализатора". Это идет как

Phenotype(std::initializer_list<uint8> c) {
  assert(c.size() <= std::size(m_array));
  std::copy(c.begin(), c.end(), m_array);
}

// used like
Phenotype p1{1, 2, 3};
Phenotype p2({1, 3, 2}); // works too
Phenotype p3(1, 2, 3); // doesn't work

Однако при такой инициализации по умолчанию будет создан массив, а затем будет использоваться оператор присваивания. Если вы стремитесь к скорости и безопасности (вы получаете ошибки времени компиляции для слишком большого количества инициализаторов!), Вы также можете использовать обычный конструктор с шаблоном с переменным числом аргументов.

Это может быть более общим, чем необходимо (хотя часто вполне достаточно initializer_list, особенно для простых целых чисел). Он выигрывает от идеальной пересылки, так что аргумент rvalue может быть перемещен в элемент массива

template<typename ...T>
Phenotype(T&&...t):m_array{ std::forward<T>(t)... } {

}

// used like
Phenotype p1{1, 2, 3}; 
Phenotype p2(1, 2, 3); // works too
Phenotype p3({1, 2, 3}); // doesn't work   

Это трудный выбор!

Редактировать Исправление, последний тоже работает, так как мы не сделали конструктор explicit, поэтому он может использовать конструктор копирования Phenotype, создавая временный объект Phenotype и скопируйте его в p3. Но это не то, что мы действительно хотим, чтобы звонки были:)

6 голосов
/ 07 ноября 2010

В C ++ 0x кажется, что вы можете создать конструктор для этого. У меня нет опыта работы с ним, но похоже, что он называется Инициализатор конструктор списка .

Контейнер может реализовать конструктор списка инициализаторов, например:

template<class E> class vector {
public:
    vector (std::initializer_list<E> s) // initializer-list constructor
    {
        reserve(s.size());  // get the right amount of space
        uninitialized_copy(s.begin(), s.end(), elem);   // initialize elements (in elem[0:s.size()))
        sz = s.size();  // set vector size
    }

    // ... as before ...
};
3 голосов
/ 07 ноября 2010

Вам необходимо использовать тип шаблона std :: initializer_list.Пример:

#include <iostream>
class X {
    public:
        X (std::initializer_list<int> list) {
        for (auto i = list.begin(); i != list.end(); i++) {
                std::cout << *i << std::endl;
            }
        }
};


int main () {
    X x = {1,2,3,4,5};
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...