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
orS
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..