10

I am trying to overload operators for std::initializer_list, but the following compiles neither in GCC 4.7.2 nor 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 says that an operator function shall have at least one parameter whose type is a class, enum, or reference to either, and the standard specifies initializer_list as a template class, so to me it seems like it should be conformant. However, apparently both Clang and GCC think I'm trying to use their non-standard block expressions.

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

Clang:

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.

Should this compile? If not, why not?

EDIT:

And not surprisingly, the November CTP of VS 2012 fails as well:

error C2143: syntax error : missing ';' before '}'
error C2059: syntax error : '{'
error C2143: syntax error : missing ';' before '{'
Seth Carnegie
  • 73,875
  • 22
  • 181
  • 249

1 Answers1

6

As far as I understand 13.5/6,

An operator function shall either be a non-static member function or be a non-member function and have at least one parameter whose type is a class, a reference to a class, an enumeration, or a reference to an enumeration

this should not be possible. Braced-init-lists are not the same as std::initializer_lists, and they're not interchangeable. The following should work, though:

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

Or this:

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

Update: To clarify, the point is that there's no rule in the language grammar that allows a braced-init-list to appear in the context suggested by the OP. Braced-init-lists can only appear in contexts where some­thing is about to be initialized, if you will.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • Why? As I said, the standard defines `initializer_list` as a class, and the standard does not say "user-defined type". – Seth Carnegie Jan 17 '13 at 00:04
  • 3
    @SethCarnegie: Well, have you tried `std::initializer_list({1,2}) + std::initializer_list({2,1})`? The braced list is not itself an initializer list; it can only be *used* to define one in certain contexts (e.g. `auto` deduction). – Kerrek SB Jan 17 '13 at 00:05
  • Overloading operators for `std::initializer_list` should be _possible_... I'm not so sure about _legal_, even when defined outside the standard namespace. – K-ballo Jan 17 '13 at 00:07
  • @K-ballo: it *is* legal. But the brace-initializer is not the same as an `std::initializer_list`. – Kerrek SB Jan 17 '13 at 00:08
  • 1
    @KerrekSB so when do brace-initialisers turn into `std::intializer_list`? I guess that is the point of the question. – Seth Carnegie Jan 17 '13 at 00:08
  • @SethCarnegie: For example, when you say `auto x = {1, 2, 3};`. Then the type of `x` is `std::initializer_list`. But those rules are laid one individually in 8.5; otherwise, brace-lists are not first-class entities in the way that identifiers and literals are. – Kerrek SB Jan 17 '13 at 00:09
  • @KerrekSB A brace-initializer initializes an `std::initializer_list` by list-initialization (§8.5.4), including function argument contexts; in other words it matches the overload. I see no problem with the code. – Potatoswatter Jan 17 '13 at 00:11
  • @Potatoswatter: But the grammar doesn't expect a braced-init-list at that point. You should try `operator+({1,2}, {2,1})`, though, but that only works with the current code, but it wouldn't work, say, with `template void operator+(T, T)`. – Kerrek SB Jan 17 '13 at 00:14
  • 1
    @KerrekSB Ah, that's right. I think that should be the first part of the answer… saying a braced-init-list isn't the same as a `std::initializer_list` is a bit like saying an integer literal isn't the same as an `int`. But the grammar is expecting an *assignment-expression*, not an *initializer-clause* which is the production including *assignment-expression* and *braced-init-list*. – Potatoswatter Jan 17 '13 at 00:22
  • @Potatoswatter: yeah, right. Feel free to post that; looks like you've got it figured out much better. – Kerrek SB Jan 17 '13 at 00:26
  • @KerrekSB All I did was verify your intuition. Your answer is right, if anyone's interested in more they can read the comment. – Potatoswatter Jan 17 '13 at 01:05