Ошибка замены шаблона со списком инициализаторов - PullRequest
0 голосов
/ 22 февраля 2019

Я знаю, как заставить работать следующий код: Я просто раскомментирую второй конструктор Printer.

Идея проста: я хочу написать конструктор / функцию, которая может принимать несколько аргументов, хранящихся в некоторой структуре данных abract, которую я могу перебирать.Я хочу, чтобы он работал по крайней мере с векторами и списками (он есть), но также и со списком инициализаторов (и это не так).

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

#include <iostream>
#include <vector>
#include <list>
#include <initializer_list>

using namespace std;

struct Printer
{
    template<class Container>
    Printer(const Container& cont)
    {
        for(const auto & e : cont)
            cout << e << " ";
        cout << endl;
    }

    //template<class T>
    //Printer(const initializer_list<T> & l)//why should I ?
    //{
    //  for(const T & e : l)
    //      cout << e << " ";
    //  cout << endl;
    //}
};

int main()
{
    vector<int> v = {1,2,3};
    Printer pv(v);
    Printer pv2 = v; //ok : not explicit

    list<char> l = {'a', 'b', 'c'};
    Printer pl(l);
    Printer pl2 = l; //ok : not explicit

    Printer pi1 = {4,5,6};      
    Printer pi2 ({4,5,6}); //same as above if explicit      
}

Но почему я должен явно писать конкретный конструктор длясписок инициализаторов?Ошибка «не удалось преобразовать« {4, 5, 6} »из« »в« Принтер ».

По сути, это говорит о том, что подстановка не работает со списком инициализаторов.Но почему?

Ответы [ 2 ]

0 голосов
/ 22 февраля 2019

A список инициализаторов в скобках (формально braced-init-list ) не является std::initializer_list.Это может быть преобразовано в один, но это не один.Это также не тип контейнера.На самом деле это не тип, а грамматическая конструкция, состоящая из следующих последовательностей символов:

{initializer-list, opt }

{}

Поэтому этот синтаксис не будет работать напрямую:

Printer pi1 = {4,5,6};      
Printer pi2 ({4,5,6}); //same as above if explicit

Если Printer был агрегат , то он мог бы выполнить агрегатную инициализацию.

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


Подробнееinfo:

То, что вы на самом деле делаете с этим синтаксисом, называется list-initialization , (агрегатная инициализация - это тип инициализации списка).Просто чтобы еще больше запутать, когда используется для инициализации типа типа T{a, b, c, ...}, он называется list initializer .Это не следует путать с std::initializer_list.

Когда в C ++ 11 был добавлен std::initializer_list, он получил специальную обработку. braced-init-list теперь можно использовать для создания временного std::initializer_list в конструкторе.Вот где вы внезапно обнаружили, что мы можем легко создать std::vector<int>, как std::vector<int> vec{1, 2, 3, 4, 5, ...};

Однако следует опасаться, что конструкторы std::initializer_list являются конструкторами с «высоким приоритетом», которые компилятор будетвыберите когда вы минимум подозреваемый .

0 голосов
/ 22 февраля 2019

Заменить

Printer pi1 = {4,5,6};      
Printer pi2 ({4,5,6}); //same as above if explicit      

на что-то вроде

Printer pi1 = vector<int>{4,5,6};      
Printer pi2 (vector<int>{4,5,6}); //same as above if explicit      
...