Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convenient C++ struct initialisation

People also ask

Do I need to initialize a struct in C?

In C, it is mandatory. How to initialize structure members? Structure members cannot be initialized with declaration.

Does C initialize structs to 0?

You don't have to initialise every element of a structure, but can initialise only the first one; you don't need nested {} even to initialise aggregate members of a structure. Anything in C can be initialised with = 0 ; this initialises numeric elements to zero and pointers null.

Are struct members initialized to zero?

If a structure variable has static storage, its members are implicitly initialized to zero of the appropriate type. If a structure variable has automatic storage, its members have no default initialization.

Can you initialize in struct?

You can also create and initialize a struct with a struct literal. An element list that contains keys does not need to have an element for each struct field. Omitted fields get the zero value for that field.


Since style A is not allowed in C++ and you don't want style B then how about using style BX:

FooBar fb = { /*.foo=*/ 12, /*.bar=*/ 3.4 };  // :)

At least help at some extent.


Designated initializes will be supported in c++2a, but you don't have to wait, because they are officialy supported by GCC, Clang and MSVC.

#include <iostream>
#include <filesystem>

struct hello_world {
    const char* hello;
    const char* world;
};

int main () 
{
    hello_world hw = {
        .hello = "hello, ",
        .world = "world!"
    };
    
    std::cout << hw.hello << hw.world << std::endl;
    return 0;
}

GCC Demo MSVC Demo

Update 20201

As @Code Doggo noted, anyone who is using Visual Studio 2019 will need to set /std:c++latest  for the "C++ Language Standard" field contained under Configuration Properties -> C/C++ -> Language.


You could use a lambda:

const FooBar fb = [&] {
    FooBar fb;
    fb.foo = 12;
    fb.bar = 3.4;
    return fb;
}();

More information on this idiom can be found on Herb Sutter's blog.


Extract the contants into functions that describe them (basic refactoring):

FooBar fb = { foo(), bar() };

I know that style is very close to the one you didn't want to use, but it enables easier replacement of the constant values and also explain them (thus not needing to edit comments), if they ever change that is.

Another thing you could do (since you are lazy) is to make the constructor inline, so you don't have to type as much (removing "Foobar::" and time spent switching between h and cpp file):

struct FooBar {
  FooBar(int f, float b) : foo(f), bar(b) {}
  int foo;
  float bar;
};

Your question is somewhat difficult because even the function:

static FooBar MakeFooBar(int foo, float bar);

may be called as:

FooBar fb = MakeFooBar(3.4, 5);

because of the promotion and conversions rules for built-in numeric types. (C has never been really strongly typed)

In C++, what you want is achievable, though with the help of templates and static assertions:

template <typename Integer, typename Real>
FooBar MakeFooBar(Integer foo, Real bar) {
  static_assert(std::is_same<Integer, int>::value, "foo should be of type int");
  static_assert(std::is_same<Real, float>::value, "bar should be of type float");
  return { foo, bar };
}

In C, you may name the parameters, but you'll never get further.

On the other hand, if all you want is named parameters, then you write a lot of cumbersome code:

struct FooBarMaker {
  FooBarMaker(int f): _f(f) {}
  FooBar Bar(float b) const { return FooBar(_f, b); }
  int _f;
};

static FooBarMaker Foo(int f) { return FooBarMaker(f); }

// Usage
FooBar fb = Foo(5).Bar(3.4);

And you can pepper in type promotion protection if you like.


Many compilers' C++ frontends (including GCC and clang) understand C initializer syntax. If you can, simply use that method.


Yet another way in C++ is

struct Point
{
private:

 int x;
 int y;

public:
    Point& setX(int xIn) { x = Xin; return *this;}
    Point& setY(int yIn) { y = Yin; return *this;}

}

Point pt;
pt.setX(20).setY(20);