Пакет расширения для инициализации std :: array с использованием std :: index_sequence - PullRequest
4 голосов
/ 24 октября 2019

Мне нужно инициализировать массив std: с N объектами, принимающими те же аргументы конструктора, что и в std::vector<T>(size_t, {args...}). Из моего поиска здесь я пришел с этим, который работает:

template<typename T, size_t... Ints, typename... Args>
std::array<T, sizeof...(Ints)> make_array_(std::index_sequence<Ints...>, Args&&... args) {
    return { (Ints, T{args...})... };
}

template<typename T, size_t N, typename... Args>
std::array<T, N> make_array(Args&&... args) {
    return make_array_<T>(std::make_index_sequence<N>(), args...);
}

struct AStruct {
    AStruct(int a, float b) : a_{ a }, b_{ b } {}
private:
    int a_; float b_;
}

int main() {
    auto anArray = make_array<AStruct, 10>(8, 5.4f);
    // etc...
}

Но я не понимаю третью строку. Как (Ints, T{args...})... перевести на T{args...}, T{args...}, T{args...}... N раз?

1 Ответ

3 голосов
/ 24 октября 2019

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

return { (0, T{args...}), (1, T{args...}), (2, T{args}) };

гдецелые числа имеют тип std::size_t.

(0, T{args...}) - это один элемент инициализатора в скобках. Это выражение, использующее оператор запятой. Оператор запятой сначала вычисляет левую часть (0), а затем правую (T{args...}) секунду, возвращая последнюю.

Поскольку оценка 0 не имеет побочного эффекта иего значение отбрасывается оператором запятой, это фактически эквивалентно

return { T{args...}, T{args...}, T{args...} };

Есть одно предупреждение. Оператор запятой может быть перегружен. Если существует перегрузка, принимающая std::size_t в качестве первого и T в качестве второго аргумента, то это будет вести себя неожиданным образом, вместо этого инициализируя возвращаемое значение, будет результат перегрузки. Этого можно избежать, приведя целое число к void (которое никогда не может появиться в качестве аргумента для перегруженного вызова оператора):

return { (void(Ints), T{args...})... };
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...