Topic: push_back<Args> and explicit constructors [Defect in the working
Author: Magnus F <magfr@lysator.liu.se>
Date: Tue, 13 Nov 2007 17:29:24 CST Raw View
Greg Herlihy wrote:
>
> Yes, clearly Foo's constructor must be explicitly called in order to
> construct the object (being added to the container) from whatever
> arguments are provided. Otherwise, a C++09 program like the one below
> - would not compile:
>
> struct A
> {
> A() {}
> A(int, int) {}
> };
>
> int main()
> {
> std::vector<A> v;
>
> v.push_back(); // adds A() to v
> v.push_back(1, 2); // adds A(1,2) to v
> }
I agree with this.
> > I want to make sure that the call to Foo(1) continues to be implicitly
> > called so that my example fails to compile in the future as well as we
> > would be degrading the value of explicit constructors otherwise.
>
> Nothing about explicit constructors has changed. Only the containers'
> declaration of puah_back() has changed - and been made more useful.
> With the new interface, objects can now be added to a container by
> constructing them "in place" - without any copying involved at all.
This is good, I really want to keep that cake as well.
> Moreover, the conversion from an int to a Foo when adding to the
> container is hardly "implicit". There is no doubt which push_back()
> method is being called here. Nor is the programmer in all likelihood
> expecting an int to reside in a container of Foo's. So the only
> plausible meaning of the push_back() call - is to construct a Foo from
> the int argument provided.
What I am saying is that maybe there should be three push_back
methods,
puch_back(const T& t) { /* same as 1998 */ }
push_back() { push_back(T()); }
push_back(U u, V v, args...) { push_back(T(u, v, args...)); }
but as you have stated above it would be nice to be able to keep the
in-place construction.
Additionally it is allowed to have any constructor, not just one
argument ones, marked explicit so the best would be if there was a way
to say (non-explicit T)(args...).
If we disregard argument packs then this can be done using
static_cast<T>(value)
so if static_cast is extended to handle argument packs then both of us
could get the result we are asking for using
push_back(Args... args) { something(T(static_cast<T>(args...)); }
> In fact, it is important to view the situation the other way around.
> Say a C++ programmer has an int - and a container of Foo's. Now, the
> programmer wants to use the int to construct a Foo and add the newly-
> constructed Foo to the end of the container. Assuming the programmer
> wants to accomplish this task in the most efficient way possible - why
> should an explicit constructor get in the way? If the explicit
> constructor did get in the way - then the programmer would be faced
> with a choice between safety and efficiency - a choice that should not
> have to be made.
I agree. I also think the static_cast idea above handles that case in
a nice way except that it is very late in the game for changes to the
language.
The big question here is not if the push_back extension is good but
what the meaning of explicit is.
> Lastly, this change breaks no existing C++ programs. True, code that
> would not have compiled in the past will now compile in C++09, due to
> this change. But the same could be said of any other extension to C++
> - and therefore does not present much of an argument against making
> the change.
I think this statement is wrong. Consider
struct S {
explicit S(long) { }
S(short) { }
};
int main()
{
std::vector<S> vs;
vs.push_back(1);
}
which is valid C++98 but ambigous using C++0x
/MF
---
[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use mailto:std-c++@ncar.ucar.edu ]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]