Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can I use the C++11 brace initialization syntax to avoid declaring trivial constructors for simple aggregates?

Let's say I have the following code:

#include <vector>

struct Foo
{
    int tag = 0;
    std::function<void ()> code;
};

int main()
{
   std::vector<Foo> v;
}

And now I want to add a new Foo item to the vector with the specific tag and code without explicitly creating a temporary. That means I must add a constructor for Foo:

struct Foo
{
    inline Foo(int t, std::function<void ()> c): tag(t), code(c) {}

    int tag = 0;
    std::function<void ()> code;
};

And now I can use emplace_back:

v.emplace_back(0, [](){});

But when I had to do this again - for the 100th time - with a newly created struct, I thought: can't I use the brace initializer? Like so:

#include <vector>

struct Foo
{
   int tag = 0;
   std::function<void ()> code;
};

int main()
{
   std::vector<Foo> v;
   v.push_back(Foo{ 0, [](){} });
}

That gives me a compilation error (cannot convert from 'initializer-list' to 'Foo'), but I hope this can be done and I've just got the syntax wrong.

like image 209
Violet Giraffe Avatar asked Jun 07 '15 17:06

Violet Giraffe


People also ask

What is brace initialization?

If a type has a default constructor, either implicitly or explicitly declared, you can use brace initialization with empty braces to invoke it. For example, the following class may be initialized by using both empty and non-empty brace initialization: C++ Copy.

Which constructor declaration is not valid in C++?

1 Answer. A constructor cannot specify any return type, not even void. A constructor cannot be final, static or abstract.

Can I define my own constructor in c++?

To customize how a class initializes its members, or to invoke functions when an object of your class is created, define a constructor. A constructor has the same name as the class and no return value. You can define as many overloaded constructors as needed to customize initialization in various ways.

What is uniform initialization in C++?

Uniform initialization is a feature in C++ 11 that allows the usage of a consistent syntax to initialize variables and objects ranging from primitive type to aggregates. In other words, it introduces brace-initialization that uses braces ({}) to enclose initializer values.


2 Answers

In C++11, you can't use an aggregate initializer with your struct because you used an equal initializer for the non-static member tag. Remove the = 0 part and it will work:

#include <vector>
#include <functional>

struct Foo
{
   int tag;
   std::function<void ()> code;
};

int main()
{
   std::vector<Foo> v;
   v.push_back(Foo{ 0, [](){} });
}
like image 187
Stefano Sanfilippo Avatar answered Nov 03 '22 10:11

Stefano Sanfilippo


According to the C++11 standard, Foo is not an aggregate, the presence of the brace-or-equal-initializer prevents it from being one.

However, this rule was changed for C++14, so if you compile your code with -std=c++14 (or whatever your compiler's equivalent setting is), Foo will be an aggregate, and your code will compile successfully.

Live demo

For a C++11 compiler, you must either remove the initializer, which will make Foo an aggregate, or provide a two argument constructor.

like image 41
Praetorian Avatar answered Nov 03 '22 11:11

Praetorian