Почему я не могу использовать = default для ctors по умолчанию со списком инициализатора члена - PullRequest
8 голосов
/ 05 июня 2019

Рассмотрим следующий класс:

class Foo {
  int a, b;
public:
  Foo() : a{1}, b{2} {} // Default ctor with member initializer list
  //Foo() : a{1}, b{2} = default; // Does not work but why?
};

( Редактировать : потому что это было упомянуто в нескольких ответах - мне известны инициализаторы членов класса,но здесь дело не в этом)

Я думаю, что второе определение ctor будет более элегантным и лучше вписывается в современный код C ++ (см. также , почему вы должны использовать =default, если вам нужнобыть явным об использовании семантики по умолчанию ).Тем не менее, ни один общий компилятор, кажется, не принимает его.И cppreference об этом ничего не говорит.

Моей первой мыслью было то, что список инициализаторов элементов каким-то образом изменяет "семантику по умолчанию", как объяснено в связанном FAQ, потому что он может или не может создавать элементы по умолчанию.Но тогда у нас будет такая же проблема для инициализаторов в классе, просто здесь Foo() = default; работает просто отлично.

Итак, почему это запрещено?

Ответы [ 4 ]

11 голосов
/ 05 июня 2019

= default; - это целое определение само по себе.Он применяется, прежде всего, грамматически:

[dcl.fct.def.general]

1 Определения функций имеютform

function-definition:
    attribute-specifier-seq<sub>opt</sub> decl-specifier-seq<sub>opt</sub> declarator virt-specifier-seq<sub>opt</sub> function-body

function-body:
    ctor-initializer<sub>opt</sub> compound-statement
    function-try-block
    = default ;
    = delete ; 

Так что это либо список инициализатора члена с составным оператором, либо просто = default;, без путаницы.

Кроме того, = default означает что-то конкретное окак каждый элемент инициализируется.Это означает , что мы явно хотим инициализировать все как конструктор, предоставленный компилятором.Это противоречит «выполнению чего-то особенного» с членами в списке инициализатора элементов конструктора.

7 голосов
/ 05 июня 2019

Выполнение a{1}, b{2} означает, что вы больше не можете указать его как default.Функция по умолчанию для [dcl.fct.def.default] / 1 определяется как

Определение функции, чье тело-функции имеет вид= default; называется явно-дефолтным определением.

И если мы проверим, что такое тело-функции в [dcl.fct.def.general] / 1 мы видим, что он содержит ctor-initializer , который является mem-initializer-list

Это означает, что вы не можете инициализировать члены, если вам нужно определение по умолчанию, предоставленное компилятором.

Что вы можете сделать, чтобы обойти это, - указать значения по умолчанию в классе напрямую, а затем объявить конструктор по умолчанию, как

class Foo {
  int a{1}, b{2};
public:
  Foo() = default;

};
3 голосов
/ 05 июня 2019

Это не дает прямого ответа на вопрос, однако это "способ" использования c ++ вместо инициализатора по умолчанию , который он

class Foo {
  int a = 1, b = 2;
public:
  Foo() = default; 
};

Синтаксис, который вы задаетепросто больше не является по умолчанию конструктором.

2 голосов
/ 05 июня 2019

Это запрещено, потому что то, что вы пытаетесь сделать по определению, означает, что он больше не является конструктором по умолчанию.И в любом случае есть более элегантный способ выполнить то, что вы хотите:

class Foo {
  int a {1};
  int b {2};
public:
  Foo() = default;
};
...