是否可以如下所示在C ++中初始化结构
struct address {
int street_no;
char *street_name;
char *city;
char *prov;
char *postal_code;
};
address temp_address =
{ .city = "Hamilton", .prov = "Ontario" };
链接here和here提到只能在C中使用这种样式。如果是这样,为什么在C ++中不能使用这种样式?是否有任何根本的技术原因导致无法在C ++中实现,还是使用这种样式的错误做法?我喜欢使用这种初始化方式,因为我的结构很大,并且这种样式使我清楚地知道了将哪个值分配给哪个成员。
[如果有其他方法可以实现相同的可读性,请与我分享。
发布此问题之前,我已经参考了以下链接
address temp_addres = {
0, // street_no
nullptr, // street_name
"Hamilton", // city
"Ontario", // prov
nullptr, // postal_code
};
#include <cstdio>
struct Group {
int x;
int y;
const char* s;
};
int main()
{
Group group {
.x = 1,
.y = 2,
.s = "Hello it works"
};
printf("%d, %d, %s", group.x, group.y, group.s);
}
struct address {
int street_no;
char *street_name;
char *city;
char *prov;
char *postal_code;
};
然后声明从原始结构类型继承的新类型的变量,并将构造函数用于字段初始化:
struct temp_address : address { temp_address() {
city = "Hamilton";
prov = "Ontario";
} } temp_address;
虽然不如C风格那么优雅...
对于局部变量,它在构造函数的开头需要一个附加的memset(this,0,sizeof(* this)),因此显然它并不差,并且@ gui13的答案更合适。((请注意,'temp_address'是'temp_address'类型的变量,但是,此新类型继承自'address',并且可以在所有需要'address'的地方使用,所以可以。)
我认为,使用这种安全方式会破坏简单性,有时安全性折衷可能太昂贵,因为简单的代码不需要复杂的设计即可保持可维护性。
作为一种替代解决方案,我建议使用lambda定义宏以简化初始化,使其看起来几乎像C样式:
struct address {
int street_no;
const char *street_name;
const char *city;
const char *prov;
const char *postal_code;
};
#define ADDRESS_OPEN [] { address _={};
#define ADDRESS_CLOSE ; return _; }()
#define ADDRESS(x) ADDRESS_OPEN x ADDRESS_CLOSE
ADDRESS宏扩展到
那样调用[] { address _={}; /* definition... */ ; return _; }()
创建并调用lambda。宏参数也是逗号分隔的,因此您需要将初始化程序放在方括号中,然后像
address temp_address = ADDRESS(( _.city = "Hamilton", _.prov = "Ontario" ));
您还可以编写通用宏初始化程序
#define INIT_OPEN(type) [] { type _={}; #define INIT_CLOSE ; return _; }() #define INIT(type,x) INIT_OPEN(type) x INIT_CLOSE
但随后通话效果不太好
address temp_address = INIT(address,( _.city = "Hamilton", _.prov = "Ontario" ));
但是您可以使用常规的INIT宏轻松定义ADDRESS宏
#define ADDRESS(x) INIT(address,x)
address temp_address = {}; // will zero all fields in C++
temp_address.city = "Hamilton";
temp_address.prov = "Ontario";
这肯定是最接近您最初想要的内容(将所有要初始化的字段都清零)。
address temp_address = { 0, 0, "Hamilton", "Ontario", 0 };
[C99故意添加了一些C99(与C89相比):
[1]可变长度数组(VLA);使用向量或某种形式的动态数组[2]指定的初始值设定项;使用构造函数
C99语法具有
指定的初始值设定项 [请参见ISO / IEC 9899:2011,N1570委员会草案-2011年4月12日]]
6.7.9初始化
initializer:
assignment-expression
{ initializer-list }
{ initializer-list , }
initializer-list:
designation_opt initializer
initializer-list , designationopt initializer
designation:
designator-list =
designator-list:
designator
designator-list designator
designator:
[ constant-expression ]
. identifier
另一方面,C ++ 11没有指定的初始值设定项 [请参阅ISO / IEC 14882:2011,N3690委员会草案-2013年5月15日]
8.5初始化程序
initializer:
brace-or-equal-initializer
( expression-list )
brace-or-equal-initializer:
= initializer-clause
braced-init-list
initializer-clause:
assignment-expression
braced-init-list
initializer-list:
initializer-clause ...opt
initializer-list , initializer-clause ...opt
braced-init-list:
{ initializer-list ,opt }
{ }
为了达到相同的效果,请使用构造函数或初始化列表:
struct address {
address() : city("Hamilton"), prov("Ontario") {}
int street_no;
char *street_name;
char *city;
char *prov;
char *postal_code;
};
struct address {
int street_no;
char *street_name;
char *city;
char *prov;
char *postal_code;
};
address ta = (ta = address(), ta.city = "Hamilton", ta.prov = "Ontario", ta);
免责声明:我不推荐这种样式
struct mp_struct_t {
public:
constexpr mp_struct_t(int member1) : mp_struct_t(member1, 0, 0) {}
constexpr mp_struct_t(int member1, int member2, int member3) : member1(member1), member2(member2), member3(member3) {}
constexpr mp_struct_t another_member(int member) { return {member1, member, member2}; }
constexpr mp_struct_t yet_another_one(int member) { return {member1, member2, member}; }
int member1, member2, member3;
};
static mp_struct_t a_struct = mp_struct_t{1}
.another_member(2)
.yet_another_one(3);
此方法也适用于全局静态变量,甚至constexpr变量。唯一的缺点是可维护性差:每次必须使用此方法初始化另一个成员时,都必须更改所有成员初始化方法。