Является ли std :: initializer_list {x, y, z} (CTAD) допустимым? - PullRequest
16 голосов
/ 17 марта 2019

При явном построении std::initializer_list<U> может ли быть выведен аргумент шаблона (U) (например, с использованием дедукции аргумента шаблона класса (CTAD))?

Другими словами, я знаю, что следующие утверждения действительны:

std::initializer_list<int> x1{1, 2, 3};
std::initializer_list<int> x2 = {1, 2, 3};
auto x3 = std::initializer_list<int>{1, 2, 3};

но допустимы ли следующие утверждения?

std::initializer_list x1{1, 2, 3};
std::initializer_list x2 = {1, 2, 3};
auto x3 = std::initializer_list{1, 2, 3};

Компиляторы не согласны с тем, можно ли вывести аргумент шаблона std::initializer_list:

#include <initializer_list>

struct s {
    s(std::initializer_list<int>);
};

void f() {
    std::initializer_list x1{1, 2, 3};         // Clang ERROR; GCC OK;    MSVC OK
    std::initializer_list x2 = {1, 2, 3};      // Clang ERROR; GCC OK;    MSVC OK
    auto x3 = std::initializer_list{1, 2, 3};  // Clang ERROR; GCC OK;    MSVC OK

    s x4(std::initializer_list{1, 2, 3});      // Clang ERROR; GCC ERROR; MSVC OK
    s x5{std::initializer_list{1, 2, 3}};      // Clang ERROR; GCC OK;    MSVC OK
    s x6 = s(std::initializer_list{1, 2, 3});  // Clang ERROR; GCC OK;    MSVC OK
    s x7 = s{std::initializer_list{1, 2, 3}};  // Clang ERROR; GCC OK;    MSVC OK
    s x8 = std::initializer_list{1, 2, 3};     // Clang ERROR; GCC OK;    MSVC OK

    void g(std::initializer_list<int>);
    g(std::initializer_list{1, 2, 3});         // Clang ERROR; GCC OK;    MSVC OK
}

(см. Этот пример в Проводник компилятора .)

Проверенные компиляторы:

  • Clang версии 7.0.0 с -std=c++17 -stdlib=libc++ и с -std=c++17 -stdlib=libstdc++
  • GCC версии 8.3 с -std=c++17
  • MSVC версия 19.16 с /std:c++17

1 Ответ

9 голосов
/ 17 марта 2019

Clang - единственный верный компилятор.Да, действительно.

Когда компилятор видит имя шаблона без параметров шаблона, он должен взглянуть на руководства по выводам шаблона и применить их к аргументам в braced-init-list.initializer_list не имеет никаких явных инструкций по выводу, поэтому он использует доступные конструкторы.

Единственные общедоступные конструкторы, которые есть у initializer_list, - это конструкторы копирования / перемещения и конструктор по умолчанию.Создание std::initializer_list из фигурного списка инициализации не выполняется с помощью общедоступных конструкторов.Это делается через list-initialization , который является только для компилятора процессом .Только компилятор может выполнить последовательность шагов, необходимых для создания одного .

. Учитывая все это, нельзя использовать CTAD в initializer_list s, если только вы не копируетеиз существующего списка.И эта последняя часть, вероятно, объясняет, как другие компиляторы заставляют ее работать в некоторых случаях.С точки зрения дедукции, они могут вывести список фигурных скобок init-списка как сам initializer_list<T>, а не как последовательность параметров, к которым нужно применить [over.match.list] , поэтому руководство по выводу видитоперация копирования.

...