Можно ли использовать синтаксис инициализации скобок C++11, чтобы избежать объявления тривиальных конструкторов для простых агрегатов?

Допустим, у меня есть следующий код:

#include <vector>

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

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

И теперь я хочу добавить новый элемент Foo в вектор с конкретными tag и code без явного создания временного объекта. Это означает, что я должен добавить конструктор для Foo:

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

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

И теперь я могу использовать emplace_back:

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

Но когда мне пришлось сделать это снова — в сотый раз — с только что созданной структурой, я подумал: а нельзя ли использовать инициализатор фигурной скобки? Вот так:

#include <vector>

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

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

Это дает мне ошибку компиляции (невозможно преобразовать из 'initializer-list' в 'Foo'), но я надеюсь, что это можно сделать, и я просто ошибся в синтаксисе.


person Violet Giraffe    schedule 07.06.2015    source источник


Ответы (2)


В C++11 вы не можете использовать агрегатный инициализатор с вашим struct, потому что вы использовали равный инициализатор для нестатического члена tag. Удалите часть = 0 и все заработает:

#include <vector>
#include <functional>

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

int main()
{
   std::vector<Foo> v;
   v.push_back(Foo{ 0, [](){} });
}
person Stefano Sanfilippo    schedule 07.06.2015
comment
Обратите внимание на это изменение в C++14, где Foo является агрегатом и может быть инициализирован с помощью агрегатной инициализации. - person chris; 07.06.2015
comment
Вау, это совершенно неожиданно. Спасибо! - person Violet Giraffe; 07.06.2015

Согласно стандарту C++11, Foo не является агрегатом, наличие координатной скобки-или-равно-инициализатора не позволяет ему быть агрегатом.

Однако это правило было изменено для C++14, поэтому, если вы скомпилируете свой код с -std=c++14 (или любой другой эквивалентной настройкой вашего компилятора), Foo будет агрегатом, и ваш код будет успешно скомпилирован.

Демо

Для компилятора C++11 необходимо либо удалить инициализатор, который сделает Foo агрегатом, либо предоставить конструктор с двумя аргументами.

person Praetorian    schedule 07.06.2015
comment
Надо дождаться Visual Studio 2015 для поддержки С++ 14 :) - person Violet Giraffe; 07.06.2015