Home > database >  Difference between using "struct S" or "S" as typename
Difference between using "struct S" or "S" as typename

Time:07-19

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.

CodePudding user response:

Writing struct S1 s1; is allowed in C for one reason: compatibility with C. C allows you to have at the same time a function called S1, so struct S1 is an explicit disambiguation. C also allows this, for backwards compatibility only.

However, in contexts where backwards compatibility is not applicable, C does not. C doesn't have constructors, for instance.

There's one other point of confusion in the question:

typedef S1 S2;
struct S2 s2;

S2 is not a struct name but an alias name, and you can't prefix an alias name with struct.

CodePudding user response:

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
}

CodePudding user response:

class-key class or struct are used only in declarations. Constructors and destructors are named as functions using class-name.

For example in this declaration

struct A
{
    A() = default;
    ~A() = default;
};

the constructor and destructor looks like function declarations that have no explicit return type.

Such a record

struct A
{
    struct A() = default;
    struct ~A() = default;
};

will be invalid. Encountering the keyword struct the compiler will consider these records as incorrect declarations.

I think that under the hood there is a desire to avoid a possible ambiguity. For example this construction

struct A()

looks like a function type that has no parameters and has the return type struct A. Or this record

struct A {}

looks like a structure definition.

Pay attention to that using an elaborated name also introduces a new type in the given scope. Consider this code snippet

struct A {};

int main()
{
    struct A;

    struct A { int x; };
}

The record struct A; in main introduces a new type in the block scope of main that hides the structure with the same name introduced in the global namespace..

  • Related