Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When is P1008 ("prohibit aggregates with user-declared constructors") useful in practice?

P1008 ("Prohibit aggregates with user-declared constructors") has become part of the C++20 standard, in order to prevent surprising behavior when using aggregate initialization:

struct X {
  int i{42};
  X() = delete;
};

int main() {
  X x2{3}; // Compiles in C++17, error in C++20
}

I agree that the above X x2{3}; statement should not compile. However, all the examples justifying P1008 that I've encountered are not realistic at all - they are purely syntactical and basically meaningless foo/bar/baz code snippets.

What problem does P1008 solve in practice? I find it hard to imagine how I would end up writing something like the above X in a real program.

Deleting the default constructor in a C++17 aggregate without providing other constructors to initialize it seems unrealistic to me.

like image 445
Vittorio Romeo Avatar asked Nov 13 '19 15:11

Vittorio Romeo


1 Answers

The most obvious case is this:

struct X
{
private:
    X() = default;
};

X x{};

This is not a type which should be able to be initialized outside of a privately accessible context. But it can be.

Now, such types might seem silly, but they're actually useful for implementing private functions that work through forwarding functions. make_shared for example cannot call constructors declared private, even if you make the make_shared template a friend. So instead, you make the constructors public, but require that the user pass an instance of a type that can only be constructed by someone with private access. So X would either be a member type of the target class or X would make the target class a friend.

like image 85
Nicol Bolas Avatar answered Nov 07 '22 06:11

Nicol Bolas