Re: Moving elements out of an initializer-list
Victor Bazarov wrote:
On 9/16/2010 4:04 PM, Johannes Schaub (litb) wrote:
Victor Bazarov wrote:
On 9/16/2010 3:05 PM, SG wrote:
On 16 Sep., 20:55, Victor Bazarov wrote:
On 9/16/2010 2:47 PM, Johannes Schaub wrote:
To "copy-initialize" just means that you initialize an object using
certain semantics - of which the most important is that only
non-explicit constructors are allowed/considered (for
list-initialization, they are considered but not allowed. For others
they are not considered in the first place). Copy-initialization
semantics apply for parameter passing, return- values and "= foo"
initialization. It does not imply that only copy constructors are
allowed to be used, despite the name.
Huh? Are you saying that somehow, if I *delete* or *make private* my
copy constructor, I will *still* be able to "copy-initialize" an
object
of my class, yet not _copy-construct_ it? And please limit your
deductions to classes only, we don't care for built-in types here.
The term "copy initialization" doesn't imply any copying (anymore).
It's just a mode of initialization that may also lead to an actual
move constructions or no copy/move construction at all in case they
are elided.
string foo ("blah"); // "direct initialization"
string bar = "blah"; // "copy initialization"
The big difference here is that in the latter case only implicit
constructors are considered and the target class type needs to be copy-
constructible OR move-constructible (or both, but this copy/move is
usually elided). We still call this kind of initialization "copy
initialization" even for move-only types. This is the standardeese
terminology which is, admittedly, a bit confusing considering movable
types.
Can you copy-initialize a stream? Is this valid code:
std::ifstream in = "filename.ext";
It's not valid in C++03, but it is valid in C++0x because streams are
movable: The thing that happens in C++0x and C++03 is that first the char
array is implicitly converted to "ifstream" and yields an ifstream
temporary. Then the "in" object is direct-initialized by that temporary.
OK, so the limitation that you run into is that 'begin' returns a
pointer to const (instead of some kind of special iterator). It would
be nice if it returned something that would have a dereference operator
returning an r-value reference, yes?
Certainly. I thought about rvalue ref qualifiers:
move_iterator<T*> begin() && { return __begin; }
T const* begin() const& { return __begin; }
But it won't work that way because it's an lvalue again when it happens to
sit in the constructor's parameter :/
You can overload the constructor though
template<typename T>
struct container {
container(initializer_list<T>&& i) { /* move ... */ }
container(initializer_list<T> const&i) { /* copy ... */ }
};
But it looks a bit weird when seen together with the copy behavior of
initializer_list (no deep copy).
For a copy-initialization example that does, in fact, not copy anything:
int n = 0;
int&rn = n; // int reference is copy-initialized.
Let's overlook the fact that it has nothing to do with
std::initializer_list<std::ifstream>, which makes an array of objects,
not references. So, you are suggesting that the 'initializer_list' has
the underlying array in which move-construction is used (not
copy-construction) for the copy-initialization of elements, yes?
The initializer_list refers to it. It does not contain it. If you copy an
initializer_list, you just copy pointers, not the real elements (see above).
The draft guarantees that the initializer_list refers to that non-const
array, if "T" is nonconstant (by the text you quoted earlier from 8.5.4/4).