Home > Mobile >  "expected primary-expression before ‘{’ token" when calling overloaded "<<"
"expected primary-expression before ‘{’ token" when calling overloaded "<<"

Time:12-22

I have a simple class 'A' with the following contents:

class A {
public:
    struct data_t {
        int32_t val;
    
        data_t(int32_t _val) :
            val(_val) {
            ;
        };
    };

    A& operator << (const data_t &data) {
        printf("[%s] %d\n", __func__, data.val);
        return *this;
    };

    void func(const data_t &data) {
        printf("[%s] %d\n", __func__, data.val);
    }
};

I tried the following codes and got:

A a;

a<<{100};          //"expected primary-expression before ‘{’ token" 
a<<A::data_t{100}; //OK.
a.func({100});     //OK.

Why a<<{100}; is NG and a.func({100}); is OK?

I don't want to use the second sentence because it is too long and complicated to read.

CodePudding user response:

Since A::data_t has a conversion constructor (a non-explicit single-argument constructor) the compiler can do implicit conversions from int32_t to A::data_t.

That means you can simply do e.g.

a << 100;

CodePudding user response:

Why a<<{100}; is NG and a.func({100}); is OK?

The grammar of the language simply only allows braced initializer lists in certain places. As operand to (arithmetic) operators in expressions it is generally not allowed, even thought one might be able to make sense of it for overloaded operators.

Braced initializer lists are potentially allowed:

  • in initializers of variables, class members, new expressions, default arguments (for function parameters and non-type template parameters)
  • after a type specifier (functional type conversion notation)
  • as arguments in function calls and template arguments
  • as right-hand side of assignment
  • as operand to return, co_return and co_yield
  • as initializer in a range-for

Assuming I didn't forget any case, they cannot be used anywhere else.

  • Related