Aggregate initialization with private copy/move constructors
I came across this while testing some stuff for another question on initializing aggregates. I'm using GCC 4.6.
When I initialize an aggregate with a list, all the members are constructed in place, without copying or moving. To wit:
int main()
{
std::array<std::array<Goo,2>,2>
a { std::array<Goo,2>{Goo{ 1, 2}, Goo{ 3, 4}} ,
std::array<Goo,2>{Goo{-1,-2}, Goo{-3,-4}} };
}
Let us confirm by making some noisy constructors:
struct Goo
{
Goo(int, int) { }
Goo(Goo &&) { std::cout << "Goo Moved." << std::endl; }
Goo(const Goo &) { std::cout << "Goo Copied." << std::endl; }
};
Upon running, no messages are printed. However, if I make the move constructor private, the compiler complains with ‘Goo::Goo(Goo&&)’ is private
, although the move constructor is patently not needed.
Does anyone know if there's a standard requirement for the move constructor to be accessible for aggregate initialization like this?
Not calling the copy or move constructor is an optimization specifically allowed by the standard (but not required).
To be consistent across compilers, an implementation must check that the constructor could have been called, if it didn't care to optimize it out.
Please allow me to follow up on Bo's answer with a modified case, again in GCC 4.6:
struct Goo
{
Goo(int x, unsigned int n) : x(x), s(new char[n]) { }
private:
Goo(const Goo &);
Goo(Goo &&);
int x;
char * s;
};
struct Foo
{
int a;
Goo g;
};
void f()
{
Foo k { 3, {1,2} }; // works
//Foo t { 1, Goo{5,6} }; // fails
//Foo r { 0, Goo(7,8) }; // fails
}
Why is the first form of in-place construction OK even without accessible copy/move constructors (note that Goo
is patently not POD or aggregate), but the latter two (functionally identical) forms aren't? Which part of the standard says that the compiler has to check for an accessible constructor in the latter two cases but not in the first case?
精彩评论