1

I came across this example from cppreference:

...

struct T3
{
    int mem1;
    std::string mem2;
    T3() {} // user-provided default constructor
}

...

This example clearly show that the given constructor is user-provided constructor since it's not explicitly defaulted or deleted on its first declaration; per [dcl.fct.def.default]/5:

[..] A function is user-provided if it is user-declared and not explicitly defaulted or deleted on its first declaration [..]

Now, Per [dcl.init.aggr]/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.8),
  • (1.3) — no virtual functions (11.7.3), and
  • (1.4) — no virtual, private, or protected base classes (11.7.2).

It seems that my class satisfy all the above requirements to be an aggregate including the point (1.1) since the given constructor is not user-declared.

So why the following code it ill-formed (tested on g++12.2 with c++20 flag):

static_assert(std::is_aggregate<T3>::value); // fail

Why static assertion is failed?

mada
  • 1,646
  • 1
  • 15
  • 2
    " A function is user-provided if it is user-declared and not explicitly defaulted or deleted on its first declaration [..]" means your constructor is user-provided (and user-declared) – 463035818_is_not_an_ai Sep 06 '22 at 12:32
  • default constructor would be `= default` – Sergey Kolesnik Sep 06 '22 at 12:33
  • All function definitions are also declarations of the function. – Some programmer dude Sep 06 '22 at 12:33
  • 4
    _"This example clearly shows that the given constructor is user-provided constructor"_ and shows also that the given constructor is _user-declared_ – mada Sep 06 '22 at 12:34
  • 1
    I don't quite follow your line of reasoning. In the beginning you state "This example clearly show that the given constructor is user-provided " and quote "A function is user-provided if it is user-declared and..." and then later "since the given constructor is not user-declared." why do you think it would be not a user-declared constructor? – 463035818_is_not_an_ai Sep 06 '22 at 12:34
  • A user provided constructor is also a user declared constrcutor. – NathanOliver Sep 06 '22 at 12:35
  • 1
    @SergeyKolesnik it is a "default constructor" just not a defaulted default constructor ;) – 463035818_is_not_an_ai Sep 06 '22 at 12:36
  • 1
    The fact that your default construct has an *empty* body doesn't mean that it isn't user-provided. Even if that's effectively the same as the defaulted (compiler-provided) constructor, it is *still* a user-provided constructor. – Adrian Mole Sep 06 '22 at 12:52
  • "Why specifying "user-provided" constructor makes the class non-aggregate?" - Because the C++ standard says so – Jesper Juhl Sep 06 '22 at 13:01

2 Answers2

8

Because a user-provided constructor is a user-declared constructor.

It is right there in the part you quote:

[..] A function is user-provided if it is user-declared and not explicitly defaulted or deleted on its first declaration [..]

Only a user-declared constructor can be a user-provided constructor. A user-declared constructor is user-provided when it is not explicitly defaulted or deleted on its first declaration.

T3() {}         // I   user-provided, user-declared 
T3() = default; // II  user-declared, not user-provided
T3() = delete;  // III user-declared, not user-provided

Terms can be a little confusing. All 3 declare a default constructor (one that can be called without parameters). Only II is a defaulted constructor (definition is generated by compiler).

PS: Thanks to @John for clarifying that also

T3();     // IV user-declared, user-provided

Is user-declared and user-provided, even if later it might be defined via

T3::T3() = default;

Because according to the definition it is user-provided when (it is user-declared and) it is not explicitly defaulted or deleted on its first declaration.

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
  • `I` is user-provided. And `struct S{ S(); } S::S() = default` is also user-provided. Right? – mada Sep 06 '22 at 13:10
  • @SofaJoe note that the specification for aggregate type doesnt mention user-provided. It rules out user-declared constructors, ie `struct S {};` is an aggregate. – 463035818_is_not_an_ai Sep 06 '22 at 13:19
  • 3
    _"And `struct S{ S(); } S::S() = default` is also user-provided."_ It is user-provided explicitly-defaulted constructor. Hence `S` is not an aggregate. – mada Sep 06 '22 at 13:22
  • 1
    The standard gives you an example: `struct nontrivial1 { nontrivial1(); // first declaration }; nontrivial1::nontrivial1() = default; // not first declaration` – mada Sep 06 '22 at 13:26
  • 1
    @SofaJoe - And `I` is user-provided user-declared constructor – mada Sep 06 '22 at 13:32
  • 1
    @SofaJoe: All things which are "user-provided" are *also* "user declared". – Nicol Bolas Sep 06 '22 at 13:35
  • 1
    @John thanks for the input, its much clearer to me now. I added a part to the answer, hope I got it right – 463035818_is_not_an_ai Sep 06 '22 at 13:36
1

Take the quote you quoted literally:

A function is user-provided if,

  • that function is user-declared function, and
  • that function is not explicitly defaulted on its first declaration, or
  • that function is not explicitly deleted on its first declaration.

Considering the quote above, and heading to [dcl.init.aggr]/1

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

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

And since your class has a user-declared constructor, which is a user-provided constructor by definition, your assertion fails.

mada
  • 1,646
  • 1
  • 15