1

According to this site /link/:

If the default constructor is explicitly declared but marked as deleted, empty brace initialization can't be used:

and it also gives an example to this:

class class_f {
public:
    class_f() = delete;
    class_f(string x): m_string { x } {} // if it is deleted, there will be no errors.
    string m_string;
};

int main()
{
    class_f cf{ "hello" };
    class_f cf1{}; // compiler error C2280: attempting to reference a deleted function
}

What I don't really understand is that, if there is no user-provided constructor, there will be no more error, even if the deleted default constructor is still there. As far as I know, if there is a user-provided constructor, there will be no implicit default constructors, but the default constructor is already deleted. So I don't know what is called in case of the value-initialization and why it is works in the example below:

#include <string>

class class_f {
public:
    class_f() = delete;
    std::string m_string;
};
int main()
{
    class_f cf1{}; // Does the implicit-default constructor is called here? But, it is deleted or not?
}
Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
Fox1942
  • 276
  • 2
  • 18
  • 2
    What version of C++ are you using? – Nicol Bolas Oct 31 '22 at 13:43
  • 1
    Refer to [how to ask](https://stackoverflow.com/help/how-to-ask) where the first step is to *"search and then research"* and you'll find plenty of related SO posts for this. For example, see [this answer](https://stackoverflow.com/a/53819762/12002570) that explains the reason. – Jason Oct 31 '22 at 13:57

1 Answers1

5

There is a difference between the C++ 17 Standard and the C++ 20 Standard according to the definition of aggregates.

According to the C++ 17 Standard this declaration

class class_f {
public:
    class_f() = delete;
    std::string m_string;
};

declares an aggregate that you may initialize using braces.

From the C++ 17 Standard (11.6.1 Aggregates)

1 An aggregate is an array or a class (Clause 12) with

(1.1) — no user-provided, explicit, or inherited constructors (15.1),

(1.2) — no private or protected non-static data members (Clause 14),

(1.3) — no virtual functions (13.3), and

(1.4) — no virtual, private, or protected base classes (13.1).

According to the C++ 20 Standard this declaration does not declare an aggregate and compiler will issue an error relative to the object initialization.

From the C++ 20 Standard (9.4.2 Aggregates)

1 An aggregate is an array or a class (Clause 11) with

(1.1) — no user-declared or inherited constructors (11.4.5),

(1.2) — no private or protected direct non-static data members (11.9),

(1.3) — no virtual functions (11.7.3), and

(1.4) — no virtual, private, or protected base classes (11.7.2).

You can try the following demonstration program

#include <iostream>
#include <iomanip>
#include <type_traits>

class class_f {
public:
    class_f() = delete;
    std::string m_string;
};

int main()
{
    std::cout << "std::is_aggregate_v<class_f> = " <<
        std::boolalpha << std::is_aggregate_v<class_f> << '\n';
}

Run it setting a compiler option to support C++ 17 and then to support C++ 20.

The type trait std::is_aggregate was introduced in C++ 17.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335