Topic: push_back<Args> and explicit constructors [Defect in the working draft]
Author: Magnus F <magfr@lysator.liu.se>
Date: Wed, 14 Nov 2007 15:27:13 CST Raw View
Magnus F wrote:
>
> 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)
Here I was wrong, static_cast do call explicit constructors.
That said, I still think it would be a good thing to have a way to
make an explicit constructor call that only allows non-explicit
constructors in the overload set. Maybe something like
weak_cast<T>(arg-list)
/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 ]
Author: Magnus F <magfr@lysator.liu.se>
Date: Wed, 7 Nov 2007 14:56:09 CST Raw View
mitsuka...@gmail.com wrote:
> On 2 nov, 16:34, Magnus F <ma...@lysator.liu.se> wrote:
> > If I read n2461 correctly then the following code:
> >
> > struct Foo {
> > explicit Foo(int) { }
> > };
> >
> > int main()
> > {
> > std::vector<Foo> fv;
> > fv.push_back(1);
> > }
> >
> > is valid and would insert a Foo(1) instance in fv.
> >
> > This would be a change from 14882:2003 where it was a compile error.
> > Is this an intended change or not?
>
> The function calls an implicit conversion not an explicit conversion,
> so the constructor signature does not match
>
Now you lost me, where is the converting constructor from int to Foo?
The problem I see is that in the 1998 standard push_back is declared
as
void vector<T, ...>::push_back(const T&)
while it, in n2461, is declared as
template <class... Args> void push_back(Args&&... args);
Now consider push_back(1), in the 1998 version the conversion sequence
is
int is _implicitly_ converted to a Foo that is inserted, but since
Foo(int) is explicit there is no valid conversion sequence so the code
is invalid.
in the n2461 version the conversion sequence is
int is handed to push_back, push_back(args) is equivalent to
a.emplace(a.end(), std::forward<Args>(args)...), that is
a.emplace(a.end(), 1), that in turn inserts an T(args), in this case
an Foo(1) and the big difference is that now Foo(1) is _explicitly_
called.
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.
On a similar note I would prefer if emplace had the same semantics so
that fv.emplace(fv.end(), 1) also gave an compile error since there is
no implicit conversion from int to Foo.
---
[ 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 ]
Author: Greg Herlihy <greghe@mac.com>
Date: Mon, 12 Nov 2007 01:31:12 CST Raw View
On Nov 7, 12:56 pm, Magnus F <ma...@lysator.liu.se> wrote:
>
> The problem I see is that in the 1998 standard push_back is declared
> as
>
> void vector<T, ...>::push_back(const T&)
>
> while it, in n2461, is declared as
>
> template <class... Args> void push_back(Args&&... args);
>
> Now consider push_back(1), in the 1998 version the conversion sequence
> is
>
> int is _implicitly_ converted to a Foo that is inserted, but since
> Foo(int) is explicit there is no valid conversion sequence so the code
> is invalid.
>
> in the n2461 version the conversion sequence is
>
> int is handed to push_back, push_back(args) is equivalent to
> a.emplace(a.end(), std::forward<Args>(args)...), that is
> a.emplace(a.end(), 1), that in turn inserts an T(args), in this case
> an Foo(1) and the big difference is that now Foo(1) is _explicitly_
> called.
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 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.
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.
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.
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.
Greg
---
[ 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 ]