C语言中结构化类型的名称S
liststruct S
在c++中也可以使用struct S
作为类型名,而不是通常的
S
。struct S {};
struct S s1; // also ok in C++
S s2; // normal way in C++
因此,假设在c++中使用struct S
或S
作为类型名是一个品味问题;-)
但是在下面的例子中,有一些地方不允许使用struct S
:
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;
}
谁能给我解释一下这种不对称是怎么回事?看起来struct S
不允许在需要作为表达式一部分的函数调用的地方使用。但是,如果类型S
也可以写成struct S
,那么使用struct S{}
作为函数调用也应该是可以的。
允许在c++中编写struct S1 s1;
有一个原因:与C兼容。C允许您同时拥有一个叫做S1
的函数,所以struct S1
是一个显式消歧。c++也允许这样做,只用于向后兼容。
然而,在向后兼容性不适用的上下文中,c++不适用。例如,C没有构造函数。
这个问题还有一个令人困惑的地方:
typedef S1 S2;
struct S2 s2;
S2
不是struct
名称,而是别名,不能在别名前加上struct
。
的假设是,在c++中使用
struct S
或S
作为类型名是一个品味问题;-)
上面的假设是错误的,因为它有例外(正如你的例子中所指出的),原因更多的是与C兼容性有关,而不是品味问题。
关键是当我们可以/不可以使用struct S1
代替S1
时,有一些规则。假设我们总是可以用struct S1
来代替S1
是错误的。
返回语句的操作数应该是表达式,但struct S1{a}
不是表达式,因此不能在返回语句中使用:
//-----vvvvvvvvvvvv----> operand is not an expression
return struct S1{a};
包含struct S1
的表达式看起来像:
return (struct S1)a;
也有情况(s),当我们需要使用struct S1
和使用S1
将不工作。下面给出了一个人为的例子:
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
}
class-key
类或结构体仅在声明中使用。构造函数和析构函数使用class-name
命名为函数。
例如在下面的声明
struct A
{
A() = default;
~A() = default;
};
构造函数和析构函数看起来像没有显式返回类型的函数声明。
这样的记录
struct A
{
struct A() = default;
struct ~A() = default;
};
无效。遇到关键字struct,编译器会认为这些记录是不正确的声明。
我认为在幕后有一种避免可能的歧义的愿望。例如这个结构
struct A()
看起来像一个函数类型,没有参数,返回类型是struct a。或者下面的记录
struct A {}
看起来像一个结构定义。
注意,使用一个详细的名称也会在给定的作用域中引入一个新的类型。考虑以下代码片段
struct A {};
int main()
{
struct A;
struct A { int x; };
}
记录struct A;
在main的块作用域中引入了一个新类型,该类型隐藏了全局命名空间中引入的相同名称的结构。