I do not understand why initializer lists cannot be used on the RHS of an operator. Consider:
class foo { };
struct bar
{
template<typename... T>
bar(T const&...) { }
};
foo& operator<<(foo& f, bar const&) { return f; }
int main()
{
foo baz;
baz << {1, -2, "foo", 4, 5};
return 0;
}
The latest Clang (gcc as well) complains:
clang.cc:14:9: error: initializer list cannot be used on the right hand side of operator '<<'
baz << {1, -2, "foo", 4, 5};
^ ~~~~~~~~~~~~~~~~~~~~
^ ~~~~~~~~~~~~~~~
Why would the C++ standard forbid this? Or put differently, why does this fail as opposed to
baz << bar{1, -2, "foo", 4, 5};
?
Indeed the final version of C++11 does not enable the use of initializer lists on the right-hand side (or left-hand side, for that matter) of a binary operator.
Firstly, initializer-lists are not expressions as defined in §5 of the Standard. The arguments of functions, as well as of binary operators, generally have to be expressions, and the grammar for expressions defined in §5 does not include the syntax for brace-init-lists (i.e. pure initializer-lists; note that a typename followed by a brace-init-list, such as
bar {2,5,"hello",7}
is an expression, though).In order to be able to use pure initializer-lists conveniently, the standard defines various exceptions, which are summarized in the following (non-normative) note:
The fourth item above explicitly allows pure initializer-lists as function arguments (which is why
operator<<(baz, {1, -2, "foo", 4, 5});
works), the fifth one allows it in subscript expressions (i.e. as argument ofoperator[]
, e.g.mymap[{2,5,"hello"}]
is legal), and the last item allows them on the right-hand side of assignments (but not general binary operators).There is no such exception for binary operators like
+
,*
or<<
, hence you can't put a pure initializer list (i.e. one that is not preceded with a typename) on either side of them.As to the reasons for this, a draft/discussion paper N2215 by Stroustrup and Dos Reis from 2007 provides a lot of insight into many of the issues with initializer-lists in various contexts. Specifically, there is a section on binary operators (section 6.2):
In other words, initializer-lists are not enabled on the right-hand side because they are not enabled on the left-hand side, and they are not enabled on the left-hand side because that would have posed too big a challenge for parsers.
I wonder if the problem could have been simplified by picking a different symbol instead of curly braces for the initializer-list syntax.