¿Por qué puedo usar operator= pero no operator== con inicializadores de llaves C++ 11?

Ver este ejemplo:

struct Foo
{
    int a;
    int b;

    bool operator == (const Foo & x)
    {
        return a == x.a && b == x.b;
    }
};

int main ()
{
    Foo a;

    a = {1, 2};

    if (a == {1, 2}) // error: expected primary-expression before ‘{’ token
    {
    }
}

La línea a={1,2} is fine. The braces are convert to a Foo to match the argument type of the implicit operator= method. It still works if operator= is user-defined.

La línea if (a=={1,2}}) errors as indicated.

¿Por qué la expresión {1,2} not convert to a Foo to match the user-defined operator== ¿método?

preguntado el 23 de abril de 13 a las 13:04

This is with g++-4.7. -

I don't see any explicit operator== in your code. Did you mean "user-defined"? -

the fact that it is called initializer list rather than expression litteral might be a clue of the fact that it is not supported on purpose (although I didn't think about it before you asked). -

Puedes escribir if (a == Foo{1, 2}) en lugar de. -

I have started a discussion in hope this limitation will be lifted in a future version. Fee free to add a comment. groups.google.com/a/isocpp.org/d/msg/std-proposals/nXjimf0amus/… -

5 Respuestas

List-initialization cannot be used as an argument to an operator en el caso general. Per Paragraph 8.5.4/1 of the C++11 Standard:

[...] List-initialization can be used

— como inicializador en una definición de variable (8.5)

— como inicializador en una nueva expresión (5.3.4)

— en una declaración de devolución (6.6.3)

— as a for-range-initializer (6.5)

- as a function argument (5.2.2)

— como subíndice (5.2.1)

— como argumento para la invocación de un constructor (8.5, 5.2.3)

— como inicializador para un miembro de datos no estático (9.2)

— en un inicializador mem (12.6.2)

- on the right-hand side of an assignment (5.17)

The last item explains why list-initialization is allowed on the right side of operator =, even though it is not allowed in general for an arbitrary operator.

Because of the fifth item above, however, it can be used as an argument to a regular function call, this way:

if (a.operator == ({1, 2}))

Respondido el 20 de junio de 20 a las 10:06

@6502: Because the Standard says so (see the paragraph I quoted) - Andy merodea

It's not that interesting really. Usted try writing a robust and unambiguous language feature to support it. - Carreras de ligereza en órbita

@6502: That's what SO would call a "non-constructive" question I guess. I can't tell the rationale. Maybe someone from the Committee could, or some user with more experience/insight than me - Andy merodea

if(a.operator==({a,b})) works, BTW. I guess this means the two forms are not as equivalent as I'd thought. - Spraff

@spraff: No, an expression (as per Clause 5 of the Standard) is something that can be evaluated and yields a value with a type and possibly side-effects (of course, expressions also require some syntax in order to be written, but that's not what I meant). On the other hand, {a, b} is not an expression - it does not have a type, it is just a language construct used for initialization. Its elements a y b are expressions, but {a, b} no es - Andy merodea

It's just simply not supported.

Initializer lists are explicitly defined to be valid in inicializaciones ([C++11: 8.5.4]), y asignaciones:

[C++11: 5.17/9]: A lista-inicial-reforzada may appear on the right-hand side of

  • an assignment to a scalar, in which case the initializer list shall have at most a single element. The meaning of x={v}, Donde T is the scalar type of the expression x, is that of x=T(v) except that no narrowing conversion (8.5.4) is allowed. The meaning of x={} is x=T().
  • an assignment defined by a user-defined assignment operator, in which case the initializer list is passed as the argument to the operator function.

There is no standard wording to allow other, arbitrary cases.

If it were allowed, in this example, the type of {1,2} would be fairly ambiguous. It would be a complicated language feature to implement.

Respondido 23 Abr '13, 13:04

What is the main logical difference between operator= y operator==? Both of them can take arbitrary types as RHS - 6502

I guess they treat assignment as a special case because of its similarities to initialisation. - Carreras de ligereza en órbita

I guess it could be defined to have whatever type the context of the statement requires. We already to this to decide whether a number is an int, float, or argument to a constructor, etc. Having {1,2} on its own need not have any meaning. - Spraff

@6502 Do not ask about "logical difference". This is C++. C++ is not a design, but a rolling snowball that accumulates hacks. - Kaz

An explicit cast is required.

if (a == (Foo){1, 2})
{
}

Respondido 23 Abr '13, 13:04

When you are using the expression containing the user defined type a and == operator Overloaded operator function gets called which as per definition you have given requires an argument of a reference of an object of class Foo

so your expression should be like a==b

where b is an object of class Foo

Here with this expression you will be able to compare data members of b and a and hence know if they are equal or not

Respondido 23 Abr '13, 13:04

No real reason.

C++ is the result of a committee effort so sometimes strange but deliberate decisions may slip through because of complex political/sociological dynamics.

C++ syntax is hard. Very hard. Almost unbelievably hard. There are rules even go like "if you can parse this arbitrarily long sequence of tokens as both this or that, then it's this".

It took many years for compilers even to simply agree on what is C++ and what is not.

In this case my wild guess is that they didn't like the idea that cases that looked very similar:

MyClass x = {...};
MyClass y; y = {...};

would be handled differently so there is a special provision for assignment to allow the syntax.

From a technical point of view I don't see what are the problems of allowing it for other operators too, and on the other hand if there are problems (e.g. for overloading, template instantiation etc.) I don't see how assignment can hope to escape them.

EDITAR

g++ allows using not only strict operator= sino también operator+=, operator-= and similar "augmented assignment". May be the logical problems happens only if you allow non-member overloads (that are forbidden for assignment and augmented assignment operators).

Respondido 23 Abr '13, 17:04

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.