Использование `= default`, позволяющее получить доступ к частному конструктору

#c #c 11

#c #c 11

Вопрос:

У меня есть код:

 class Key
{
private:
    // If I use the = default keyword here, the line "Key a = {};" compiles
    // If I instead use Key() {}, that same line does not compile (as the constructor is private)
    Key() = default;

    Key(Key const amp;) = default;
    Key(Key amp;amp;) = default;

    Key amp; operator=(Key const amp;) = default;
    Key amp; operator=(Key amp;amp;) = default;
};

int main()
{
    // This line compiles when = default is used, but not when an empty constructor is used
    Key a = {};
    return 0;
}
  

В чем, в частности, разница между конструктором по умолчанию и пустым конструктором в этом конкретном экземпляре? Кроме того, я бы хотел, чтобы это НЕ компилировалось, является ли явное написание моего собственного пустого конструктора единственным способом сделать это здесь? Примечание: это было протестировано как с GCC 8.3, так и с Clang 10.0 с идентичными результатами.

Ответ №1:

Когда конструктор по умолчанию default редактируется, до C 20, этот код компилируется, поскольку ваш класс с конструктором по умолчанию является агрегированным, и вы можете инициализировать агрегаты с помощью инициализации агрегата

 Key a = {}; // interpreted as aggregate initialization and bypasses access qualifier on constructor
  

Этот код не будет компилироваться на C 20 или выше, поскольку конструктор по умолчанию делает его неагрегатным:

 Key a = {}; // interpreted as calling a constructor, since Key is no longer an aggregate.
  

В этом случае компилятор пытается фактически вызвать конструктор и не может, поскольку конструктор является закрытым.

Когда у вас есть

 Key() { };
  

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

Комментарии:

1. В этой статье подробно рассматривается непостоянный агрегат на C с 11 по C 20.