Search code examples
c++structconstructordeclaration

Difference between using "struct S" or "S" as typename


In the C language the name of a structured type S ist struct S.

In C++ one can also use struct S as typename instead of S as usual for

struct S {};

struct S s1; // also ok in C++
S s2; // normal way in C++

So, the assumption is, that using struct S or S as typename in C++ is a matter of taste ;-)

But in the following example there are places where struct S is not allowed:

struct S1 {
    S1(int x = 0) : x{x} {}
    int x{};
};

typedef S1 S2;

template<typename T>
auto foo(T a) {
//    T::_; // T is deduced to `S` in all cases
    return S1{a};
//    return struct S1{a}; // NOK
}

int main() {
//    foo(struct S1{i}); // NOK
    
    S1 s1;
    foo(s1);
    
    struct S1 s2{2};
    foo(s2);
    
    foo(1);

//    struct S2 s20; // NOK
    S2 s21;    
}

Can anyone explain to me what this unsymmetry is about? It looks like struct S is not allowed where a ctor call as part of an expression is needed. But if a type S could also be written as struct S it should also be ok to use struct S{} as a ctor call.


Solution

  • the assumption is, that using struct S or S as typename in C++ is a matter of taste ;-)

    The above assumption is wrong as there are exceptions to it(as also noted in your example) and the reason has more to do with C compatibility than a matter of taste.

    The point is that there are rules for when we can/cannot use struct S1 as a replacement for just S1. And assuming that we can always use struct S1 as a replacement for S1 is wrong.


    The operand of the return statement should be an expression but struct S1{a} is not an expression and hence cannot be used in the return statement:

    //-----vvvvvvvvvvvv----> operand is not an expression
    return struct S1{a};
    

    An expression involving struct S1 would look something like:

    return (struct S1)a;
    

    There are also situation(s) when we need to use struct S1 and using just S1 won't work. A contrived example is given below:

    struct S1 
    {
        
    };
    int S1() 
    {
        std::cout<<"function called"<<std::endl;
        return 5;
    }
    
    int main() 
    {
         //S1 s; // ERROR: This won't work unless we use struct S1
         
         struct S1 s2; //WORKS
    }