Related
Is there a way to specify the default constructor of an enum class?
I am using an enum class to specify a set of values which are allowable for a particular datatype in a library: in this case, it's the GPIO pin id numbers of a Raspberry Pi. It looks something like this:
enum class PinID : int {N4 = 4, N17 = 17, /* ...etc... */ }
The point of me doing this instead just of using, say, an int is to ensure that code is safe: I can static_assert (or otherwise compile-time ensure -- the actual method used is not important to me) things like that someone hasn't made a spelling error (passing a 5 instead of a 4, etc), and I get automatic error messages for type mismatches, etc.
The problem then is that enum class has a default constructor that -- for compatibility's sake with C's enums I assume (since they have the same behaviour) -- initializes to the enum class equivalent of 0. In this case, there is no 0 value. This means that a user making a declaration/definition like:
PinID pid = PinID();
is getting an enumerator that isn't explicitly defined (and doesn't even seem to "exist" when one looks at the code), and can lead to runtime errors. This also means that techniques like switching over the values of explicitly defined enumerators is impossible without having an error/default case -- something I want to avoid, since it forces me to either throw or do something like return a boost::optional, which are less amenable to static analysis.
I tried to define a default constructor to no avail. I (desperately) tried to define a function which shares the name of the enum class, but this (rather unsurprisingly) resulted in strange compiler errors. I want to retain the ability to cast the enum class to int, with all N# enumerators mapping to their respective #, so merely "defining", say, N4 = 0 is unacceptable; this is for simplicity and sanity.
I guess my question is two-fold: is there a way to get the kind of static safety I'm after using enum class? If not, what other possibilities would one prefer? What I want is something which:
is default constructable
can be made to default construct to an arbitrary valid value
provides the "finite set of specified" values afforded by enum classes
is at least as type safe as an enum class
(preferably) doesn't involve runtime polymorphism
The reason I want default constructability is because I plan to use boost::lexical_cast to reduce the syntactic overhead involved in conversions between the enum class values, and the actual associated strings which I output to the operating system (sysfs in this case); boost::lexical_cast requires default constructability.
Errors in my reasoning are welcome -- I am beginning to suspect that enum classes are the right object for the wrong job, in this case; clarification will be offered if asked. Thank you for your time.
A type defined with enum class or enum struct is not a a class but a scoped enumeration and can not have a default constructor defined. The C++11 standard defines that your PinID pid = PinID(); statement will give a zero-initialization. Where PinID was defined as a enum class. It also allows enum types in general to hold values other than the enumerator constants.
To understand that PinID() gives zero initialization requires reading standard sections 3.9.9, 8.5.5, 8.5.7 and 8.5.10 together:
8.5.10 - An object whose initializer is an empty set of parentheses, i.e., (), shall be value-initialized
8.5.7 - To value-initialize an object of type T means: ... otherwise, the object is zero-initialized.
8.5.5 - To zero-initialize an object or reference of type T means: — if T is a scalar type (3.9), the object is set to the value 0 (zero), taken as an integral constant expression, converted to T;
3.9.9 - States that enumeration types are part of the set of types known as scalar types.
A possible solution:
To meet your points 1 to 5 you could write a class along the lines of:
class PinID
{
private:
PinID(int val)
: m_value(val)
{}
int m_value;
public:
static const PinID N4;
static const PinID N17;
/* ...etc... */
PinID()
: m_value(N4.getValue())
{}
PinID(const PinID &id)
: m_value(id.getValue())
{}
PinID &operator = (const PinID &rhs)
{
m_value = rhs.getValue();
return *this;
}
int getValue() const
{
return m_value;
}
// Attempts to create from int and throw on failure.
static PinID createFromInt(int i);
friend std::istream& operator>>(std::istream &is, PinID &v)
{
int candidateVal(0);
is >> candidateVal;
v = PinID::createFromInt(candidateVal);
return is;
}
};
const PinID PinID::N4 = PinID(4);
/* ...etc... */
That can give you something that you would have to make specific efforts to get an invalid values into. The default constructor and stream operator should allow it to work with lexical_cast.
Seems it depends how critical the operations on a PinID are after it's creation whether it's worth writing a class or just handling the invalid values everywhere as the value is used.
An enum class is just a strongly-typed enum; it's not a class. C++11 just reused the existing class keyword to avoid introducing a new keyword that would break compatibility with legacy C++ code.
As for your question, there is no way to ensure at compile time that a cast involves a proper candidate. Consider:
int x;
std::cin >> x;
auto p = static_cast<PinID>(x);
This is perfectly legal and there is no way to statically ensure the console user has done the right thing.
Instead, you will need to check at runtime that the value is valid. To get around this in an automated fashion, one of my co-workers created an enum generator that builds these checks plus other helpful routines given a file with enumeration values. You will need to find a solution that works for you.
I know that this question is dated and that it already has an accepted answer but here is a technique that might help in a situation like this with some of the newer features of C++
You can declare this class's variable either non static or static, it can be done in several ways permitted on support of your current compiler.
Non Static:
#include <iostream>
#include <array>
template<unsigned... IDs>
class PinIDs {
private:
const std::array<unsigned, sizeof...(IDs)> ids { IDs... };
public:
PinIDs() = default;
const unsigned& operator[]( unsigned idx ) const {
if ( idx < 0 || idx > ids.size() - 1 ) {
return -1;
}
return ids[idx];
}
};
Static: - There are 3 ways to write this: (First One - C++11 or 14 or higher) last 2 (c++17).
Don't quote me on the C++11 part; I'm not quite sure when variadic templates or parameter packs were first introduced.
template<unsigned... IDs>
class PinIDs{
private:
static const std::array<unsigned, sizeof...(IDs)> ids;
public:
PinIDs() = default;
const unsigned& operator[]( unsigned idx ) const {
if ( idx < 0 || idx > ids.size() - 1 ) {
return -1;
}
return ids[idx];
}
};
template<unsigned... IDs>
const std::array<unsigned, sizeof...(IDs)> PinIDs<IDs...>::ids { IDs... };
template<unsigned... IDs>
class PinIDs{
private:
static constexpr std::array<unsigned, sizeof...(IDs)> ids { IDs... };
public:
PinIDs() = default;
const unsigned& operator[]( unsigned idx ) const {
if ( idx < 0 || idx > ids.size() - 1 ) {
return -1;
}
return ids[idx];
}
};
template<unsigned... IDs>
class PinIDs{
private:
static inline const std::array<unsigned, sizeof...(IDs)> ids { IDs... };
public:
PinIDs() = default;
const unsigned& operator[]( unsigned idx ) const {
if ( idx < 0 || idx > ids.size() - 1 ) {
return -1;
}
return ids[idx];
}
};
All examples above either non-static or static work with the same use case below and provide the correct results:
int main() {
PinIDs<4, 17, 19> myId;
std::cout << myId[0] << " ";
std::cout << myId[1] << " ";
std::cout << myId[2] << " ";
std::cout << "\nPress any key and enter to quit." << std::endl;
char c;
std::cin >> c;
return 0;
}
Output
4 17 19
Press any key and enter to quit.
With this type of class template using a variadic parameter list, you don't have to use any constructor but the default. I did add bounds checking into the array so that the operator[] doesn't exceed bounds of its size; I could of threw an error but with unsigned type I just simply returned -1 as an invalid value.
With this type, there is no default as you have to instantiate this kind of object via template parameter list with a single or set of values. If one wants to they can specialize this class with a single parameter of 0 for a default type. When you instantiate this type of object; it is final as in it can not be changed from its declaration. This is a const object and still holds to be default constructible.
This question already has answers here:
Designated initializers in C++20
(2 answers)
Closed 4 months ago.
Is it possible to initialize structs in C++ as indicated below:
struct address {
int street_no;
char *street_name;
char *city;
char *prov;
char *postal_code;
};
address temp_address = { .city = "Hamilton", .prov = "Ontario" };
The links here and here mention that it is possible to use this style only in C. If so why is this not possible in C++? Is there any underlying technical reason why it is not implemented in C++, or is it bad practice to use this style. I like using this way of initializing because my struct is big and this style gives me clear readability of what value is assigned to which member.
Please share with me if there are other ways through which we can achieve the same readability.
I have referred the following links before posting this question:
C/C++ for AIX
C Structure Initialization with Variable
Static structure initialization with tags in C++
C++11 Proper Structure Initialization
If you want to make it clear what each initializer value is, just split it up on multiple lines, with a comment on each:
address temp_addres = {
0, // street_no
nullptr, // street_name
"Hamilton", // city
"Ontario", // prov
nullptr, // postal_code
};
After my question resulted in no satisfying result (because C++ doesn't implement tag-based init for structures), I took the trick I found here: Are members of a C++ struct initialized to 0 by default?
For you it would amount to do that:
address temp_address = {}; // will zero all fields in C++
temp_address.city = "Hamilton";
temp_address.prov = "Ontario";
This is certainly the closest to what you wanted originally (zero all the fields except those you want to initialize).
As others have mentioned this is designated initializer.
This feature is part of C++20
The field identifiers are indeed C initializer syntax. In C++ just give the values in the correct order without the field names. Unfortunately this means you need to give them all (actually you can omit trailing zero-valued fields and the result will be the same):
address temp_address = { 0, 0, "Hamilton", "Ontario", 0 };
This feature is called designated initializers. It is an addition to the C99 standard. However, this feature was left out of the C++11. According to The C++ Programming Language, 4th edition, Section 44.3.3.2 (C Features Not Adopted by C++):
A few additions to C99 (compared with C89) were deliberately not adopted in C++:
[1] Variable-length arrays (VLAs); use vector or some form of dynamic array
[2] Designated initializers; use constructors
The C99 grammar has the designated initializers [See ISO/IEC 9899:2011, N1570 Committee Draft - April 12, 2011]
6.7.9 Initialization
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
On the other hand, the C++11 does not have the designated initializers [See ISO/IEC 14882:2011, N3690 Committee Draft - May 15, 2013]
8.5 Initializers
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 }
{ }
In order to achieve the same effect, use constructors or initializer lists:
I know this question is quite old, but I found another way of initializing, using constexpr and 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, member3}; }
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);
This method also works for global static variables and even constexpr ones.
The only disadvantage is the bad maintainability: Everytime another member has to be made initializable using this method, all member initialization methods have to be changed.
You can just initialize via a constructor:
struct address {
address() : city("Hamilton"), prov("Ontario") {}
int street_no;
char *street_name;
char *city;
char *prov;
char *postal_code;
};
I might be missing something here, by why not:
#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);
}
You can even pack Gui13's solution into single initialization statement:
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);
Disclaimer: I don't recommend this style
It's not implemented in C++. (also, char* strings? I hope not).
Usually if you have so many parameters it is a fairly serious code smell. But instead, why not simply value-initialize the struct and then assign each member?
Inspired by this really neat answer: (https://stackoverflow.com/a/49572324/4808079)
You can do lamba closures:
// 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 $;
}();
}
Or, if you want to be very fancy
#define DesignatedInit(T, ...)\
[]{ T ${}; __VA_ARGS__; return $; }()
class SomeClass {
static const inline SomeBigStruct voiceAmps = DesignatedInit(
ModulationTarget,
$.min = 0,
$.nickname = "Bobby",
$.bloodtype = "O-",
);
}
There are some drawbacks involved with this, mostly having to do with uninitialized members. From what the linked answers comments say, it compiles efficiently, though I have not tested it.
Overall, I just think it's a neat approach.
I found this way of doing it for global variables, that does not require to modify the original structure definition :
struct address {
int street_no;
char *street_name;
char *city;
char *prov;
char *postal_code;
};
then declare the variable of a new type inherited from the original struct type and use the constructor for fields initialisation :
struct temp_address : address { temp_address() {
city = "Hamilton";
prov = "Ontario";
} } temp_address;
Not quite as elegant as the C style though ...
For a local variable it requires an additional memset(this, 0, sizeof(*this)) at the beginning of the constructor, so it's clearly not worse it and #gui13 's answer is more appropriate.
(Note that 'temp_address' is a variable of type 'temp_address', however this new type inherit from 'address' and can be used in every place where 'address' is expected, so it's OK.)
In C++ the C-style initializers were replaced by constructors which by compile time can ensure that only valid initializations are performed (i.e. after initialization the object members are consistent).
It is a good practice, but sometimes a pre-initialization is handy, like in your example. OOP solves this by abstract classes or creational design patterns.
In my opinion, using this secure way kills the simplicity and sometimes the security trade-off might be too expensive, since simple code does not need sophisticated design to stay maintainable.
As an alternative solution, I suggest to define macros using lambdas to simplify the initialization to look almost like C-style:
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
The ADDRESS macro expands to
[] { address _={}; /* definition... */ ; return _; }()
which creates and calls the lambda. Macro parameters are also comma separated, so you need to put the initializer into brackets and call like
address temp_address = ADDRESS(( _.city = "Hamilton", _.prov = "Ontario" ));
You could also write generalized macro initializer
#define INIT_OPEN(type) [] { type _={};
#define INIT_CLOSE ; return _; }()
#define INIT(type,x) INIT_OPEN(type) x INIT_CLOSE
but then the call is slightly less beautiful
address temp_address = INIT(address,( _.city = "Hamilton", _.prov = "Ontario" ));
however you can define the ADDRESS macro using general INIT macro easily
#define ADDRESS(x) INIT(address,x)
In GNUC++ (seems to be obsolete since 2.5, a long time ago :) See the answers here: C struct initialization using labels. It works, but how?), it is possible to initialize a struct like this:
struct inventory_item {
int bananas;
int apples;
int pineapples;
};
inventory_item first_item = {
bananas: 2,
apples: 49,
pineapples: 4
};
You have
The standard initialization list
address temp_address {
/* street_no */,
/* street_name */,
...
/* postal_code */
};
address temp_address2 = {
/* street_no */,
/* street_name */,
...
/* postal_code */
}
The dot notation
address temp_address;
temp_address.street_no = ...;
temp_address.street_name = ...;
...
temp_address.postal_code = ...;
The designated aggregate initialization, where the initialization list contains that labels of each member of the structure (see documentation) available from C++20 onward.
Treating a struct like a C++ class - in C++ structures are actually special types of classes, where all members are public (unlike a standard C++ class where all members are private if not specified otherwise explicitly) as well as that when using inheritance they default to public:
struct Address {
int street_no;
...
char* postal_code;
Address (int _street_no, ... , char* _postal_code)
: street_no(_street_no),
...
postal_code(_postal_code)
{}
}
...
Address temp_address ( /* street_no */, ..., /* postal_code */);
When it comes to the way you initialize your structure you should consider the following aspects:
Portability - different compilers, different degree of C++ standard completeness and different C++ standards altogether do limit your options. If you have to work with let's say a C++11 compiler but want to use the C++20 designated aggregate initialization you are out of luck
Readability - what is more readable: temp_address.city = "Toronto" or temp_address { ..., "Toronto", ... }? Readability of your code is very important. Especially when you have large structures (worse - nested ones), having unlabeled values all over the place is just asking for trouble
Scalability - anything that depends on a specific order is not a good idea. The same goes for lack of labels. You want to move a member up or down the address space of the structure? Good luck with an unlabeled initialization list (hunting down swapped values in structure initialization is a nightmare)... You want to add a new member? Again good luck with anything that depends on a specific order.
While the dot notation means you type more the benefits you get from using it outweigh this issue and as such I can recommend it unless you have a small structure that is future-proof in terms of lack of changes in its structure, in which case you can afford to go with an initialization list. Remember: whenever working with other people writing code that is easy to follow is essential.
I faced a similar problem today, where I have a struct that I want to fill with test data which will be passed as arguments to a function I'm testing. I wanted to have a vector of these structs and was looking for a one-liner method to initialize each struct.
I ended up going with a constructor function in the struct, which I believe was also suggested in a few answers to your question.
It's probably bad practice to have the arguments to the constructor have the same names as the public member variables, requiring use of the this pointer. Someone can suggest an edit if there is a better way.
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;
Which I used in in my test function to call the function being tested with various arguments like this:
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);
}
It is possible, but only if the struct you're initializing is a POD (plain old data) struct. It cannot contain any methods, constructors, or even default values.
Using Visual Studio 2013 and C++ compiler to write yet another linked list and happened across this by trial and error. Is this specific to Visual C++ or part of the standard?
I really like this syntax. It's super clean. If you've written a linked list lib before you know you can chase pointers around until your brain is tied in knots. This syntax though is crystal clear.
Lots of this stuff with static initializer values, but using function args as initializers? Haven't seen that yet.
It would be comforting to know if the GCC C/C++ compiler produces the expected result. Anyone?
typedef struct link_in_list {
struct link_in_list *next;
int32_t key;
int32_t value;
} LINK, *pLINK;
// ----------------------------------------------------------------------------
pLINK prepend_list(pLINK head, int32_t key, int32_t value)
{
if (NULL == head) {
// initialize with a constant, variable, and expression
return new LINK{ NULL, key, (key * key) };
} else {
// initialize with stack variables
return new LINK{ head, key, value };
}
}
This is called list initialization and was introduced in C++11. It's different from direct initialization in a bunch of ways that I would like to point out:
int x{3.5}; // illegal - narrowing
int x(3.5); // fine, x is 3, but does this make sense?
T fun(); // this is a function returning a T
T fun{}; // this is a default constructed object
// of type T
std::vector<int> v(10, 20); // 10 elems: 20, 20, 20, ..., 20
std::vector<int> v{10, 20}; // 2 elems: 10, 20
But outside of those cases, it's pretty similar to direct initialization. So no, it's not compiler specific - as long as the compiler in question supports the new language standard.
One addition in functionality is that if T is an "aggregate" (that is, an array, or a class type that has no private/protected members, no user-provided constructors, no base classes, no virtual methods), then list initialization is equivalent to aggregate initialization.
That is:
struct Foo {
int a;
char b;
double c;
};
int i = 1;
char c = 'b';
double d = 42.;
Foo f{i, c, d};
Foo g = {i, c, d};
Those lines are equivalent.
I was creating a vector of my bitpacked vectors, called xor_funcs, using the length and value constructor for vector.
This is the test that failed:
TEST(vectorInit, size3) {
const xor_func temp{false, {0,0,0}};
vector<xor_func> arr{3, temp};
for(xor_func& f : arr) {
EXPECT_EQ(3, f.size()) << f;
}
for(int i = 0; i < 3; i++) {
ASSERT_EQ(3, arr[i].size()) << "for i=" << i;
arr[i].set(i);
}
}
It seems that the size() call is accessing uninitialized memory, for vectors of length 3 or more, but not ones of size 2. Valgrind confirms that the memory is not recently stack'd, malloc'd or free'd.
The xor_func is defined as such:
class xor_func {
private:
boost::dynamic_bitset<> bitset;
bool negated;
public:
xor_func(const bool neg, const std::initializer_list<int> lst);
// That's defined in cpp
xor_func(const size_t size) : bitset(size), negated(false) {}
// Disallow the trivial constructor, since I don't want
// any 0 length xor_funcs existing by default.
// xor_func() : bitset(), negated(false) {}
xor_func(const bool negated, const boost::dynamic_bitset<> bitset)
: bitset(bitset), negated(negated) {}
// That's all the constructors.
// Snip
}
I didn't do anything with the default copy and move constructors.
What is going on, and why does my test fail?
As dyb said, vector<xor_func> arr{3, temp}; was being interpreted as
vector<xor_func> arr({xor_func{3}, temp}), as the 3 could be converted into a xor_func by a constructor implicitly, and then it could choose the initializer list version of the constructor to call.
If you look at Is C++11 Uniform Initialization a replacement for the old style syntax?, you can see that one of the downsides of uniform initialization syntax is exactly this bug. A more trivial example is
// std::string constructor prototype for reference
// fill (6)
string (size_t n, char c);
void main() {
string myString{65, 'B'};
cout << myString << endl;
}
This will print out "AB", instead of "BBBBBB...BBB", as it can convert 65 to 'A', and then it's as if we wrote myString{'A', 'B'}. To fix it, simply don't try and use the uniform initialization syntax for this call and replace it with
string myString(65, 'B');
Another way I could fix this bug is to change the constructor xor_func(const size_t size) to be explicit xor_func(const size_t size), which prevents the compiler from implicitly converting the 3 to an xor_func.
Oh, there's another great answer What does the explicit keyword mean in C++.
This question already has answers here:
Designated initializers in C++20
(2 answers)
Closed 4 months ago.
Is it possible to initialize structs in C++ as indicated below:
struct address {
int street_no;
char *street_name;
char *city;
char *prov;
char *postal_code;
};
address temp_address = { .city = "Hamilton", .prov = "Ontario" };
The links here and here mention that it is possible to use this style only in C. If so why is this not possible in C++? Is there any underlying technical reason why it is not implemented in C++, or is it bad practice to use this style. I like using this way of initializing because my struct is big and this style gives me clear readability of what value is assigned to which member.
Please share with me if there are other ways through which we can achieve the same readability.
I have referred the following links before posting this question:
C/C++ for AIX
C Structure Initialization with Variable
Static structure initialization with tags in C++
C++11 Proper Structure Initialization
If you want to make it clear what each initializer value is, just split it up on multiple lines, with a comment on each:
address temp_addres = {
0, // street_no
nullptr, // street_name
"Hamilton", // city
"Ontario", // prov
nullptr, // postal_code
};
After my question resulted in no satisfying result (because C++ doesn't implement tag-based init for structures), I took the trick I found here: Are members of a C++ struct initialized to 0 by default?
For you it would amount to do that:
address temp_address = {}; // will zero all fields in C++
temp_address.city = "Hamilton";
temp_address.prov = "Ontario";
This is certainly the closest to what you wanted originally (zero all the fields except those you want to initialize).
As others have mentioned this is designated initializer.
This feature is part of C++20
The field identifiers are indeed C initializer syntax. In C++ just give the values in the correct order without the field names. Unfortunately this means you need to give them all (actually you can omit trailing zero-valued fields and the result will be the same):
address temp_address = { 0, 0, "Hamilton", "Ontario", 0 };
This feature is called designated initializers. It is an addition to the C99 standard. However, this feature was left out of the C++11. According to The C++ Programming Language, 4th edition, Section 44.3.3.2 (C Features Not Adopted by C++):
A few additions to C99 (compared with C89) were deliberately not adopted in C++:
[1] Variable-length arrays (VLAs); use vector or some form of dynamic array
[2] Designated initializers; use constructors
The C99 grammar has the designated initializers [See ISO/IEC 9899:2011, N1570 Committee Draft - April 12, 2011]
6.7.9 Initialization
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
On the other hand, the C++11 does not have the designated initializers [See ISO/IEC 14882:2011, N3690 Committee Draft - May 15, 2013]
8.5 Initializers
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 }
{ }
In order to achieve the same effect, use constructors or initializer lists:
I know this question is quite old, but I found another way of initializing, using constexpr and 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, member3}; }
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);
This method also works for global static variables and even constexpr ones.
The only disadvantage is the bad maintainability: Everytime another member has to be made initializable using this method, all member initialization methods have to be changed.
You can just initialize via a constructor:
struct address {
address() : city("Hamilton"), prov("Ontario") {}
int street_no;
char *street_name;
char *city;
char *prov;
char *postal_code;
};
I might be missing something here, by why not:
#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);
}
You can even pack Gui13's solution into single initialization statement:
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);
Disclaimer: I don't recommend this style
It's not implemented in C++. (also, char* strings? I hope not).
Usually if you have so many parameters it is a fairly serious code smell. But instead, why not simply value-initialize the struct and then assign each member?
Inspired by this really neat answer: (https://stackoverflow.com/a/49572324/4808079)
You can do lamba closures:
// 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 $;
}();
}
Or, if you want to be very fancy
#define DesignatedInit(T, ...)\
[]{ T ${}; __VA_ARGS__; return $; }()
class SomeClass {
static const inline SomeBigStruct voiceAmps = DesignatedInit(
ModulationTarget,
$.min = 0,
$.nickname = "Bobby",
$.bloodtype = "O-",
);
}
There are some drawbacks involved with this, mostly having to do with uninitialized members. From what the linked answers comments say, it compiles efficiently, though I have not tested it.
Overall, I just think it's a neat approach.
I found this way of doing it for global variables, that does not require to modify the original structure definition :
struct address {
int street_no;
char *street_name;
char *city;
char *prov;
char *postal_code;
};
then declare the variable of a new type inherited from the original struct type and use the constructor for fields initialisation :
struct temp_address : address { temp_address() {
city = "Hamilton";
prov = "Ontario";
} } temp_address;
Not quite as elegant as the C style though ...
For a local variable it requires an additional memset(this, 0, sizeof(*this)) at the beginning of the constructor, so it's clearly not worse it and #gui13 's answer is more appropriate.
(Note that 'temp_address' is a variable of type 'temp_address', however this new type inherit from 'address' and can be used in every place where 'address' is expected, so it's OK.)
In C++ the C-style initializers were replaced by constructors which by compile time can ensure that only valid initializations are performed (i.e. after initialization the object members are consistent).
It is a good practice, but sometimes a pre-initialization is handy, like in your example. OOP solves this by abstract classes or creational design patterns.
In my opinion, using this secure way kills the simplicity and sometimes the security trade-off might be too expensive, since simple code does not need sophisticated design to stay maintainable.
As an alternative solution, I suggest to define macros using lambdas to simplify the initialization to look almost like C-style:
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
The ADDRESS macro expands to
[] { address _={}; /* definition... */ ; return _; }()
which creates and calls the lambda. Macro parameters are also comma separated, so you need to put the initializer into brackets and call like
address temp_address = ADDRESS(( _.city = "Hamilton", _.prov = "Ontario" ));
You could also write generalized macro initializer
#define INIT_OPEN(type) [] { type _={};
#define INIT_CLOSE ; return _; }()
#define INIT(type,x) INIT_OPEN(type) x INIT_CLOSE
but then the call is slightly less beautiful
address temp_address = INIT(address,( _.city = "Hamilton", _.prov = "Ontario" ));
however you can define the ADDRESS macro using general INIT macro easily
#define ADDRESS(x) INIT(address,x)
In GNUC++ (seems to be obsolete since 2.5, a long time ago :) See the answers here: C struct initialization using labels. It works, but how?), it is possible to initialize a struct like this:
struct inventory_item {
int bananas;
int apples;
int pineapples;
};
inventory_item first_item = {
bananas: 2,
apples: 49,
pineapples: 4
};
You have
The standard initialization list
address temp_address {
/* street_no */,
/* street_name */,
...
/* postal_code */
};
address temp_address2 = {
/* street_no */,
/* street_name */,
...
/* postal_code */
}
The dot notation
address temp_address;
temp_address.street_no = ...;
temp_address.street_name = ...;
...
temp_address.postal_code = ...;
The designated aggregate initialization, where the initialization list contains that labels of each member of the structure (see documentation) available from C++20 onward.
Treating a struct like a C++ class - in C++ structures are actually special types of classes, where all members are public (unlike a standard C++ class where all members are private if not specified otherwise explicitly) as well as that when using inheritance they default to public:
struct Address {
int street_no;
...
char* postal_code;
Address (int _street_no, ... , char* _postal_code)
: street_no(_street_no),
...
postal_code(_postal_code)
{}
}
...
Address temp_address ( /* street_no */, ..., /* postal_code */);
When it comes to the way you initialize your structure you should consider the following aspects:
Portability - different compilers, different degree of C++ standard completeness and different C++ standards altogether do limit your options. If you have to work with let's say a C++11 compiler but want to use the C++20 designated aggregate initialization you are out of luck
Readability - what is more readable: temp_address.city = "Toronto" or temp_address { ..., "Toronto", ... }? Readability of your code is very important. Especially when you have large structures (worse - nested ones), having unlabeled values all over the place is just asking for trouble
Scalability - anything that depends on a specific order is not a good idea. The same goes for lack of labels. You want to move a member up or down the address space of the structure? Good luck with an unlabeled initialization list (hunting down swapped values in structure initialization is a nightmare)... You want to add a new member? Again good luck with anything that depends on a specific order.
While the dot notation means you type more the benefits you get from using it outweigh this issue and as such I can recommend it unless you have a small structure that is future-proof in terms of lack of changes in its structure, in which case you can afford to go with an initialization list. Remember: whenever working with other people writing code that is easy to follow is essential.
I faced a similar problem today, where I have a struct that I want to fill with test data which will be passed as arguments to a function I'm testing. I wanted to have a vector of these structs and was looking for a one-liner method to initialize each struct.
I ended up going with a constructor function in the struct, which I believe was also suggested in a few answers to your question.
It's probably bad practice to have the arguments to the constructor have the same names as the public member variables, requiring use of the this pointer. Someone can suggest an edit if there is a better way.
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;
Which I used in in my test function to call the function being tested with various arguments like this:
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);
}
It is possible, but only if the struct you're initializing is a POD (plain old data) struct. It cannot contain any methods, constructors, or even default values.