C++;结构初始化 是否可以在C++中初始化结构,如下面的 struct address { int street_no; char *street_name; char *city; char *prov; char *postal_code; }; address temp_address = { .city = "Hamilton", .prov = "Ontario" }; >链接并提到只有在C中才可能使用这种样式,如果是这样,为什么C++中不可能使用这种样式?在C++中没有实现它的根本原因,还是使用这种样式是不好的实践。我喜欢使用这种初始化方式,因为我的结构很大,而且这种样式使我能够清楚地了解分配给哪个成员的值
如果有其他方法可以达到同样的可读性,请与我分享 在发布此问题之前,我已经参考了以下链接C++;结构初始化 是否可以在C++中初始化结构,如下面的 struct address { int street_no; char *street_name; char *city; char *prov; char *postal_code; }; address temp_address = { .city = "Hamilton", .prov = "Ontario" }; >链接并提到只有在C中才可能使用这种样式,如果是这样,为什么C++中不可能使用这种样式?在C++中没有实现它的根本原因,还是使用这种样式是不好的实践。我喜欢使用这种初始化方式,因为我的结构很大,而且这种样式使我能够清楚地了解分配给哪个成员的值,c++,C++,如果有其他方法可以达到同样的可读性,请与我分享 在发布此问题之前,我已经参考了以下链接 字段标识符实际上是C初始值设定项语法。在C++中,只需在没有字段名称的情况下以正确的顺序给出值。不幸的是,这意味着您需要提供所有字段(实际上您可以省略尾随的零值字段,结果将是相同的): 它没有在C++中实现。(还有,char*strings?我希望不会) 通常,如果您有这么多的参数,这是一个相当严重的代码气味。但是,为什么不简单地对结构进行值初始化,然后分配每个成员呢?如果您想弄清楚每个初始值是什么,
字段标识符实际上是C初始值设定项语法。在C++中,只需在没有字段名称的情况下以正确的顺序给出值。不幸的是,这意味着您需要提供所有字段(实际上您可以省略尾随的零值字段,结果将是相同的):
它没有在C++中实现。(还有,
char*
strings?我希望不会)
通常,如果您有这么多的参数,这是一个相当严重的代码气味。但是,为什么不简单地对结构进行值初始化,然后分配每个成员呢?如果您想弄清楚每个初始值是什么,只需将其分成多行,并在每行上添加注释:
address temp_addres = {
0, // street_no
nullptr, // street_name
"Hamilton", // city
"Ontario", // prov
nullptr, // postal_code
};
结果不令人满意(因为C++没有实现基于标签的init结构),所以我在这里找到了这个窍门:
对你来说,这相当于:address temp_address = {}; // will zero all fields in C++
temp_address.city = "Hamilton";
temp_address.prov = "Ontario";
这当然是最接近您最初想要的(除您想要初始化的字段外,将所有字段归零)。您甚至可以将GUI 13的解决方案打包到单个初始化语句中:
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 address {
address() : city("Hamilton"), prov("Ontario") {}
int street_no;
char *street_name;
char *city;
char *prov;
char *postal_code;
};
我知道这个问题已经很老了,但我找到了另一种初始化方法,使用constexpr和currying:
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变量。
唯一的缺点是可维护性差:每次必须使用此方法初始化另一个成员时,都必须更改所有成员的初始化方法。我今天遇到了一个类似的问题,我想用测试数据填充一个结构,这些数据将作为参数传递给我正在测试的函数。我想得到这些结构的一个向量,并寻找一个一行方法来初始化每个结构 最后,我在结构中使用了一个构造函数,我相信在对您的问题的一些回答中也提到了这一点 让构造函数的参数与公共成员变量具有相同的名称可能是一种不好的做法,需要使用
this
指针。如果有更好的方法,有人可以建议编辑
typedef struct testdatum_s {
public:
std::string argument1;
std::string argument2;
std::string argument3;
std::string argument4;
int count;
testdatum_s (
std::string argument1,
std::string argument2,
std::string argument3,
std::string argument4,
int count)
{
this->rotation = argument1;
this->tstamp = argument2;
this->auth = argument3;
this->answer = argument4;
this->count = count;
}
} testdatum;
我在我的测试函数中使用它来调用正在测试的函数,参数如下:
std::vector<testdatum> testdata;
testdata.push_back(testdatum("val11", "val12", "val13", "val14", 5));
testdata.push_back(testdatum("val21", "val22", "val23", "val24", 1));
testdata.push_back(testdatum("val31", "val32", "val33", "val34", 7));
for (std::vector<testdatum>::iterator i = testdata.begin(); i != testdata.end(); ++i) {
function_in_test(i->argument1, i->argument2, i->argument3, i->argument4m i->count);
}
struct inventory_item {
int bananas;
int apples;
int pineapples;
};
inventory_item first_item = {
bananas: 2,
apples: 49,
pineapples: 4
};
std::向量测试数据;
testdata.push_back(testdatum(“val11”、“val12”、“val13”、“val14”、“5”);
testdata.push_back(testdatum(“val21”、“val22”、“val23”、“val24”、1));
testdata.push_back(testdatum(“val31”、“val32”、“val33”、“val34”、7));
对于(std::vector::iterator i=testdata.begin();i!=testdata.end();++i){
_测试中的函数_(i->argument1,i->argument2,i->argument3,i->argument4mi->count);
}
这是可能的,但前提是您正在初始化的结构是POD(普通旧数据)结构。它不能包含任何方法、构造函数,甚至默认值。在C++中,< P> > C风格的初始化器被构造函数取代,编译时间可以确保只执行有效的初始化(即初始化后对象成员是一致的)。
这是一个很好的实践,但有时预初始化很方便,如您的示例中所示。OOP通过抽象类或函数来解决这个问题
在我看来,使用这种安全的方式扼杀了简单性,有时安全性权衡可能过于昂贵,因为简单的代码不需要复杂的设计来保持可维护性
作为替代解决方案,我建议使用lambdas定义宏,以简化初始化,使其看起来几乎像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" ));
但是,您可以使用general INIT宏轻松定义ADDRESS宏
#define ADDRESS(x) INIT(address,x)
我发现这种方法适用于全局变量,不需要修改原始结构定义:
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”的地方使用,所以它是可以的。)此功能称为指定初始值设定项。它是对C99标准的补充。但是,C++11没有提供此功能。根据C++程序设计语言,第四版,44.3.3.2节(C++未采用的C特性): 在C++中故意不采用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
另一方面
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 }
{ }
#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);
}
// Nobody wants to remember the order of these things
struct SomeBigStruct {
int min = 1;
int mean = 3 ;
int mode = 5;
int max = 10;
string name;
string nickname;
... // the list goes on
}
class SomeClass {
static const inline SomeBigStruct voiceAmps = []{
ModulationTarget $ {};
$.min = 0;
$.nickname = "Bobby";
$.bloodtype = "O-";
return $;
}();
}
#define DesignatedInit(T, ...)\
[]{ T ${}; __VA_ARGS__; return $; }()
class SomeClass {
static const inline SomeBigStruct voiceAmps = DesignatedInit(
ModulationTarget,
$.min = 0,
$.nickname = "Bobby",
$.bloodtype = "O-",
);
}
struct inventory_item {
int bananas;
int apples;
int pineapples;
};
inventory_item first_item = {
bananas: 2,
apples: 49,
pineapples: 4
};