4

I defined the following class:

class A {
    int a;
public:
    A(int _a = 0) :a(_a){}
    A(initializer_list<int> il) :a(il.size()){}
    friend A operator+(const A& a1, const A& a2);
};
A operator+(const A& a1, const A& a2){ return A(); }

The following client code

A a;
operator+(a,{3, 4, 5});

can compile, but the following

A a;
a + {3, 4, 5};

can not compile. The error message is "error C2059: syntax error : '{'" and "error C2143: syntax error : missing ';' before '{'".

Both two client codes try to do the implicit type conversion, from initialization list {3,4,5} to class A, but the first succeeds while the second snippet fails. I can not understand why.

Can you explain it?

I'm using MS Visual Studio 2013 Update 4.

[Edit] Here is a follow up, after reading the comments and other related materials. I think my question can now be reduced to the following: I got it that brace-init-list is not allowed in the RHS of an binary expression, and also that it IS allowed in a function call. The thing is, I think the binary expression, say, arg1 + arg2 is converted internally by the compiler to a function call operator+ (arg1, arg2), especially when arg1 is a class type. So at this point, there is no difference between binary expression and function call. As a result, the only explanation I can figure out is that there is a preventing rule applied before such a binary-expression-to-function-call conversion, that checks particularly whether the second argument is a brace-init-list or not. If it is, conversion to an equivalent function call will be forbidden and an error is produced. I wonder if these conjectures are real and if it is, is it written somewhere specifically in the C++ standard? Thank everyone who participated in my question.

13
  • That reminds me somehow of an operator << problem I had a while ago. Somehow and for some operators, the standard prohibits implicit type conversions of arguments. The lesson I learned back then is: Screw "syntactic sugar". Commented Apr 25, 2015 at 4:35
  • stackoverflow.com/questions/27826824/… <<-- the answers there might also apply to your question somehow Commented Apr 25, 2015 at 4:39
  • Answer is: {3,4,5} is not a class type. Hence no implicit conversion. Commented Apr 25, 2015 at 4:47
  • 1
    Syntactically, {3, 4, 5} is a braced-init-list. A braced-init-list is not an expression; the syntax only allows it in a limited number of places, it cannot appear everywhere an integer literal may appear, say. In particular, it's allowed as an argument to a function call, and explicitly allowed on the right hand side of an assignment operator (5.18/9), but not any other operators. Commented Apr 25, 2015 at 4:55
  • 2
    There is a good answer here: stackoverflow.com/q/11420448/951890 Commented Apr 25, 2015 at 12:22

2 Answers 2

3

The error message generated by clang is quite clear:

error: initializer list cannot be used on the right hand side of operator '+'

Looking into the C++11 standard, I find this (8.5.4/1 [dcl.init.list]):

Note: List-initialization can be used

  • as the initializer in a variable definition (8.5)
  • as the initializer in a new expression (5.3.4)
  • in a return statement (6.6.3)
  • as a function argument (5.2.2)
  • as a subscript (5.2.1)
  • as an argument to a constructor invocation (8.5, 5.2.3)
  • as an initializer for a non-static data member (9.2)
  • in a mem-initializer (12.6.2)
  • on the right-hand side of an assignment (5.17)

So I guess braced-init-list can only be used in the cases listed above. operator+(a, {1, 2, 3}) works because of case 4. a = {1, 2, 3} works because of the last case. But nothing is mentioned about a + {1, 2, 3}. So no.

Sign up to request clarification or add additional context in comments.

2 Comments

But why can't we explain a + {1, 2, 3} as operator+(a, {1, 2, 3}) and apply the case 4? This conversion (from arg1+arg2 to operator+(arg1,arg2)) is an ordinary concept of overloaded operator definition for classes.
@user280121 Well, I'm not a compiler writer. So I cannot give you an exact answer. C++ parsing is complex. Just interpret a + {1, 2, 3} to operator+(a, {1, 2, 3})? While it sounds reasonable to us common folks as C++ users, it is not as simple as that to compiler writers who know what is really going on under the hood.
0

I tried to look in the standard to find out the reason why it is not allowed to write expression + braced-init-list and the first I have found is a comment in an example

§5.1.2 (4)

a braced-init-list is not an expression

and it does not fulfill the requirements for a primary-expression. But it can be used in a postfix-expression:

postfix-expression:
    simple-type-specifier braced-init-list
    typename-specifier braced-init-list

Binary operators like + expect expressions to the left and right and thus, expression + braced-init-list does not fit into the c++-grammer.

But a braced-init-list can appear on the right-hand side of an assignment, since it expects an initializer-clause:

assignment-expression:
    logical-or-expression assignment-operator initializer-clause
initializer-clause:
    assignment-expression
    braced-init-list

Thus, you could rewrite your example using a operator+=:

A operator+=(A& a1, const A& a2){ return A(); }
int main() {
    A a;
    a + A{3, 4, 5};
    a += {3, 4, 5};
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.