Подтвердить что ты не робот

Почему мой шаблон не принимает список инициализаторов

Я создал шаблон следующим образом

template<typename T>
void f(T const& t) { }

Я хотел, чтобы это вызывалось контейнерами, а также списками инициализаторов. Я думал, что это будет initializer_list<int>, когда вызывается следующим образом.

f({1, 2, 3});

Но GCC ведет себя так, как будто это не соответствует стандартам

m.cpp: In function 'int main()':
m.cpp:6:25: warning: deducing 'const T' as 'const std::initializer_list<int>'
m.cpp:4:6: warning:   in call to 'void f(const T&) [with T = std::initializer_list<int>]'
m.cpp:6:25: warning:   (you can disable this with -fno-deduce-init-list)

Может кто-нибудь объяснить, как я могу сделать эту работу без предупреждений? Спасибо!

4b9b3361

Ответ 1

"вещь", подобная {1,2,3}, не квалифицируется как выражение. У него нет типа. Поэтому никакого вычитания типа не производится. Но С++ 0x делает явное исключение для "auto", поэтому

auto x = {1,2,3};

действительно работает, а decltype (x) будет initializer_list<int>. Но это специальное правило, которое применяется только к авто. Я думаю, они хотели создать такие петли, как эти

for (int x : {2,3,5,7,11}) {
   ...
}

поскольку этот тип цикла использует специальное правило.

Что касается решения проблемы, вы можете добавить перегрузку initializer_list<T> в качестве "обертки":

template<class T>
inline void outer(initializer_list<T> il) {
   inner(il);
}

Я не тестировал это, но мое нынешнее понимание заключается в том, что он должен работать.

Ответ 2

Хорошо, в документации говорится, что

Эта опция присутствует, потому что этот вывод является расширением текущей спецификации в рабочем проекте С++ 0x, и есть некоторая проблема с потенциальными проблемами разрешения перегрузки.

Эта информация может быть просто устаревшей (согласно источнику, она была обновлена ​​в 2008 году). Насколько я понимаю, вывод был включен в GCC, но с ожиданием, что более поздний проект стандарта удалит правило или, по крайней мере, ограничит его.

Ответ 3

Может кто-нибудь объяснить, как я могу сделать эту работу без предупреждений?

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

f<initializer_list<int>>({1, 2, 3});

Это не очень, но это может избежать предупреждения без использования аргументов командной строки компилятора.

Я бы, вероятно, добавил комментарий, в котором объясняется, что вы не полагаетесь на компилятор, который выдает правильный тип из-за слабостей в некоторых версиях GCC.