Можно ли использовать агрегатную инициализацию C ++ для создания экземпляра класса, который реализует интерфейс? - PullRequest
0 голосов
/ 08 декабря 2018

Я надеюсь, что кто-то может дать мне техническую информацию о том, почему следующее не будет компилироваться, и, если возможно, обойти это.

У меня есть существующая структура с именем Foo, и код, который использует списки инициализатора длясоздавать экземпляры Foo.Этот код компилируется и работает:

struct Foo {
    int id1;
    int id2;
};

int main()
{
    Foo f({1,2});

    return f.id1;
}

Я бы хотел, чтобы Foo реализовал интерфейс в будущем:

struct Interface {
    // All pure virtual methods, but this won't compile even if empty
};

struct Foo : public Interface{
    int id1;
    int id2;
};

int main()
{
    Foo f({1,2});

    return f.id1;
}

Этот код больше не компилируется, с ошибками в

cannot convert argument 1 from 'initializer list' to 'const _Ty &'

(Ошибка изменяется в зависимости от вашего точного компилятора.)

Я нашел этот раздел стандарта, касающийся инициализации агрегата:

[dcl.init.aggr] / 1 Агрегат - это массив или класс (раздел 12), в котором 1.1 нет пользовательских, явных или унаследованных конструкторов (15.1), 1.2 нет частных или защищенных нестатических элементов данных (пункт 14), 1.3 нет виртуальных функций(13.3) и 1.4 нет виртуальных, частных или защищенных базовых классов (13.1).

Хотя на самом деле я не уверен, что здесь происходит агрегатная инициализация.Может кто-нибудь объяснить возникшую ошибку и, если возможно, предложить изменения, которые я мог бы внести в интерфейс?У меня есть несколько существующих структур, которым нужен этот интерфейс, и много существующего кода, который использует эту форму инициализации, и я хотел бы переписать как можно меньше.Спасибо!

Ответы [ 2 ]

0 голосов
/ 08 декабря 2018

@ ShafikYaghmour объяснил, почему, когда Interface пусто, агрегатная инициализация не может быть выполнена, как это было раньше.

Но если Interface имеет виртуальные функции, как предлагается в вопросе, производный классс Interface не будет агрегатом .Поэтому класс, который реализует Interface и содержит элементы данных как Foo, должен реализовывать конструктор.Самый простой способ, который я вижу (который, в зависимости от «тривиальности» элементов данных, может быть не самым эффективным с точки зрения скорости), заключается в следующем:

struct Interface {
   // All pure virtual methods, but this won't compile even if empty
   virtual void bar() =0;
   };

struct Foo_data{ //change the name of the aggregate
  int id1;
  int id2;
  };

struct Foo
  :Interface  //Foo has virtual function => Foo is not an aggregate
  ,Foo_data
  {
  Foo() =default;
  Foo(Foo_data data):Foo_data(std::move(data)){}//a constructor must be provided
  void bar() override {}
  };

int main(){
  Foo f({1,2});
  return f.id1;
  }
0 голосов
/ 08 декабря 2018

Вам нужно инициализировать базовый класс, даже если он пуст:

Foo f({{},1,2});

увидеть его вживую на кресте

Далее в стандарте в разделеВы имеете в виду, что мы можем видеть пример этого в [dcl.init.aggr] p4.2 :

struct base1 { int b1, b2 = 42; };
struct base2 {
  base2() {
   b3 = 42;
 }
 int b3;
};

struct derived : base1, base2 {
 int d;
};

derived d1{{1, 2}, {}, 4};
derived d2{{}, {}, 4};

инициализирует d1.b1 с 1, d1.b2 с 2, d1.b3 с 42, d1.d с 4 и d2.b1 с 0, d2.b2 с 42, d2.b3 с 42, d2.d с 4. - конец примера]

Также см. [dcl.init.aggr] p2 , в котором объясняются элементы совокупности:

Элементы совокупности:

- для массива, элементы массива в порядке возрастания индекса или
- для класса, прямые базовые классы в порядке объявления, за которыми следуют прямые нестатические члены данных ([класс.mem]), которые не являются членами анонимного объединения, в порядке объявления.

и [dcl.init.aggr] p3 говорит:

Когда агрегат инициализируетсясписок инициализаторов, как указано в [dcl.init.list], элементы списка инициализаторов берутся в качестве инициализаторов для элементов агрегата....

Обратите внимание, что в ответе предполагается, что C ++ 17 или выше, поскольку до C ++ 17 агрегату не разрешалось иметь базовый класс .

...