Можно ли перегружать операторы для литералов initializer_list?

Я пытаюсь перегрузить операторы для std::initializer_list, но следующее не компилируется ни в GCC 4.7.2, ни в Clang 3.2:

#include <initializer_list>

void operator+(const std::initializer_list<int>&, const std::initializer_list<int>&);

int main() {
   {1, 2} + {3, 4};
}

13.5/6 говорит, что операторная функция должна иметь по крайней мере один параметр, тип которого является классом, перечислением или ссылкой на любой из них, а стандарт определяет initializer_list как класс-шаблон, поэтому мне кажется, что он должен соответствовать. Однако, по-видимому, и Clang, и GCC думают, что я пытаюсь использовать их нестандартные блочные выражения.

ССЗ:

Compilation finished with errors:
source.cpp: In function 'int main()':
source.cpp:7:8: warning: left operand of comma operator has no effect [-Wunused-value]
source.cpp:7:9: error: expected ';' before '}' token
source.cpp:7:9: warning: right operand of comma operator has no effect [-Wunused-value]
source.cpp:7:13: error: expected primary-expression before '{' token
source.cpp:7:13: error: expected ';' before '{' token

Звон:

Compilation finished with errors:
source.cpp:7:5: warning: expression result unused [-Wunused-value]
   {1, 2} + {3, 4};
    ^
source.cpp:7:9: error: expected ';' after expression
   {1, 2} + {3, 4};
        ^
        ;
source.cpp:7:8: warning: expression result unused [-Wunused-value]
   {1, 2} + {3, 4};
       ^
source.cpp:7:13: error: expected expression
   {1, 2} + {3, 4};
            ^
2 warnings and 2 errors generated.

Это должно компилироваться? Если нет, то почему?

ИЗМЕНИТЬ:

И неудивительно, что ноябрьская CTP VS 2012 также не работает:

error C2143: syntax error : missing ';' before '}'
error C2059: syntax error : '{'
error C2143: syntax error : missing ';' before '{'

person Seth Carnegie    schedule 16.01.2013    source источник


Ответы (1)


Насколько я понимаю 13.5/6,

Операторная функция должна быть либо нестатической функцией-членом, либо функцией, не являющейся членом, и иметь хотя бы один параметр, тип которого является классом, ссылкой на класс, перечислением или ссылкой на перечисление< /сильный>

это не должно быть возможно. Списки инициализации в фигурных скобках — это не то же самое, что std::initializer_list, и они не взаимозаменяемы. Однако следующее должно работать:

std::initializer_list<int>({1,2}) + std::initializer_list<int>({2,1})

Или это:

operator+({1,2}, {2,1})

Обновление: Чтобы уточнить, дело в том, что в грамматике языка нет правила, позволяющего отображать список инициализации в фигурных скобках в контексте, предложенном OP. Braced-init-lists могут появляться только в контекстах, где что-то должно быть инициализировано, если хотите.

person Kerrek SB    schedule 17.01.2013
comment
Почему? Как я уже сказал, стандарт определяет initializer_list как класс, и стандарт не говорит о пользовательском типе. - person Seth Carnegie; 17.01.2013
comment
@SethCarnegie: А ты пробовал std::initializer_list<int>({1,2}) + std::initializer_list<int>({2,1})? Список в фигурных скобках сам по себе не является списком инициализаторов; его можно использовать только для определения в определенных контекстах (например, auto дедукции). - person Kerrek SB; 17.01.2013
comment
Перегрузка операторов для std::initializer_list должна быть возможна... Я не уверен в законности, даже если они определены вне стандартного пространства имен. - person K-ballo; 17.01.2013
comment
@K-ballo: это законно. Но инициализатор фигурной скобки — это не то же самое, что std::initializer_list. - person Kerrek SB; 17.01.2013
comment
@KerrekSB, так когда инициализаторы фигурных скобок превращаются в std::intializer_list? Думаю, в этом суть вопроса. - person Seth Carnegie; 17.01.2013
comment
@SethCarnegie: Например, когда вы говорите auto x = {1, 2, 3};. Тогда тип x равен std::initializer_list<int>. Но эти правила заложены по отдельности в 8.5; в противном случае скобочные списки не являются первоклассными сущностями, как идентификаторы и литералы. - person Kerrek SB; 17.01.2013
comment
@KerrekSB Инициализатор скобок инициализирует std::initializer_list с помощью инициализации списка (§8.5.4), включая контексты аргументов функции; другими словами, он соответствует перегрузке. Не вижу проблем с кодом. - person Potatoswatter; 17.01.2013
comment
@Potatoswatter: Но в этот момент грамматика не ожидает списка инициализации в фигурных скобках. Вы должны попробовать operator+({1,2}, {2,1}), но это работает только с текущим кодом, но не будет работать, скажем, с template <typename T> void operator+(T, T). - person Kerrek SB; 17.01.2013
comment
@KerrekSB Ах, верно. Я думаю, что это должно быть первой частью ответа… сказать, что список инициализации в фигурных скобках не то же самое, что std::initializer_list, немного похоже на то, что сказать, что целочисленный литерал не то же самое, что int. Но грамматика ожидает выражение-присваивания, а не предложение-инициализатора, которое является произведением, включающим выражение-присваивания и в скобках- список инициализации. - person Potatoswatter; 17.01.2013
comment
@Potatoswatter: да, верно. Не стесняйтесь публиковать это; похоже, вы разобрались гораздо лучше. - person Kerrek SB; 17.01.2013
comment
@KerrekSB Все, что я сделал, это проверил твою интуицию. Ваш ответ правильный, если кому-то интересно больше, они могут прочитать комментарий. - person Potatoswatter; 17.01.2013