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?
}
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.