push_back<Args> and explicit constructors - c++

This is a discussion on push_back<Args> and explicit constructors - c++ ; If I read n2461 correctly then the following code: struct Foo { explicit Foo(int) { } }; int main() { std::vector&lt;Foo&gt; fv; fv.push_back(1); } is valid and would insert a Foo(1) instance in fv. This would be a change from ...

+ Reply to Thread
Results 1 to 6 of 6

push_back<Args> and explicit constructors

  1. Default push_back<Args> and explicit constructors

    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?

    ---
    [ 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 ]


  2. Default Re: push_back<Args> and explicit constructors

    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?
    >
    > ---
    > [ comp.std.c++ is moderated. To submit articles, try just posting with ]
    > [ your news-reader. If that fails, use mailto:std-...@ncar.ucar.edu ]
    > [ --- Please see the FAQ before posting. --- ]
    > [ FAQ:http://www.comeaucomputing.com/csc/faq.html ]


    The function calls an implicit conversion not an explicit conversion,
    so the constructor signature does not match

    ---
    [ 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 ]


  3. Default Re: push_back<Args> and explicit constructors [Defect in the working draft]


    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, ...>:ush_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 ]


  4. Default Re: push_back<Args> and explicit constructors [Defect in the working draft]

    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, ...>:ush_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 ]


  5. Default Re: push_back<Args> and explicit constructors [Defect in the workingdraft]

    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 ]


  6. Default Re: push_back<Args> and explicit constructors [Defect in the working draft]


    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 ]


+ Reply to Thread

Similar Threads

  1. explicit template args
    By Application Development in forum c++
    Replies: 3
    Last Post: 08-22-2007, 09:58 AM
  2. Re: SmartPointer & Inheritance & Explicit Constructors
    By Application Development in forum c++
    Replies: 38
    Last Post: 07-05-2007, 02:20 PM
  3. Re: SmartPointer & Inheritance & Explicit Constructors
    By Application Development in forum c++
    Replies: 0
    Last Post: 06-17-2007, 06:15 AM
  4. explicit copy constructors.
    By Application Development in forum c++
    Replies: 8
    Last Post: 04-08-2007, 01:57 PM
  5. explicit and not explicit constructors
    By Application Development in forum c++
    Replies: 2
    Last Post: 03-23-2007, 09:12 PM