#include <initializer_list>
#include <iostream>
using namespace std;
struct Y {};
struct X
{
X(initializer_list<Y>) { cout << "yay" << endl; }
explicit X() { cout << "boo" << endl; }
};
X f()
{
return {};
}
int main()
{
f();
return 0;
}
This prints out "boo". Why doesn't it print out "yay" ?
Is there anyway to differentiate the following two constructions:
X()
X{}
or
return X();
return {};
or
void g(const X&)
g(X())
g({})
Thanks.
It uses the default constructor because list initialization with
{}
is meant to be a short form of value initialization always, disregarding of other constructors, even if they are initializer list constructors.The
X()
is always value initialization, whileX{}
is only value initialization ifX
has a default constructor. If it is an aggregate, thenX{}
is aggregate initialization (initializing the members ofX
by a{}
recursively). If it only has initializer list constructors and no default constructors, thenX()
is invalid andX{}
could be validEssentially, what
X{}
does depends on whatX
is. ButX()
always value initializes.Something subtle to mention... In
return {}
the target is copy-list-initialized, while inreturn X();
first direct-initializes anX
. But even though it is copy-list-initialized, it can use anexplicit
default constructor, because value initialization doesn't care aboutexplicit
. However when you doreturn {}
and you try to use an explicit non-default constructor you will error outYou could be a bit more explicit:
return {};
will always use a default constructor if there is one.return X({});
orreturn {{}};
will construct from an empty initialiser list.No. They are not different constructs.
The primary purpose of the {} constructor syntax was to introduce uniform initialization, to have initialization work the same everywhere. If there was a difference between them, it wouldn't be uniform.
If you want to use the empty initializer list constructor, you have to state that you're passing an initializer list explicitly. Like this:
return initializer_list<Y>{};
Of course, one of the other purposes of uniform initialization is to not have to type out typenames so much, so you can achieve the same effect withreturn {{}};