Topic: Tuple Constructors


Author: =3D?ISO-8859-1?Q?Daniel_Kr=3DFCgler?=3D <daniel.kruegler@googlemail.c=.om>
Date: Wed, 11 Aug 2010 22:49:12 CST
Raw View
On Aug 10, 4:14 am, Scott Meyers <NeverR...@aristeia.com> wrote:
> >From the FCD:
>
> template <class... Types>
> class tuple {
> public:
>  ...
>  explicit tuple(const Types&...);
>  template <class... UTypes> explicit tuple(UTypes&&...);
>  ...
> };
>
> Why do we need the first of these constructors?  The second one will
> accept almost anything, and it permits rvalue arguments to be moved
> into their corresponding tuple elements, while the first one will
> require that such arguments be copied.

There is a small corner-case where the first overload is useful, see
below.

> The only thing I can see that the first constructor provides is
> support for brace initialization syntax:
>
>  tuple<T1, T2, T3> t = { expr1, expr2, expr3 };    // calls 1st ctor ab=
ove
>
> Is that all it gives us?

This expression should not be well-formed given any of the two
constructors, because both are explicit constructors, thus only
the direct initialization

tuple<T1, T2, T3> t{ expr1, expr2, expr3 };

will work in either case. Which c'tor is selected, depends on the
value-categories of the expressions expr1, expr2, and expr3.

> It's also my impression that the second constructor will be a better
> match for any set of arguments except a set where all arguments are
> const lvalues, provided the brace initialization syntax is not used:
>
>  tuple<T1, T2, T3> t(expr1, expr2, expr3);    // calls 2nd ctor above
unless
>                                               // all exprs are const
lvalues
>
> Is that the case?

Yes.

> All clarification appreciated.

There is a single additional use for the non-template c'tor of
tuple, namely to be able to take care of the integral null pointer
constant if the destination is a pointer or pointer to member.
Ideally the template constructor should be constrained, see
e.g.

http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#1324

Consider:

#include <tuple>

std::tuple<void*> t(0);

If the template c'tor were constrained as described above,
it would be sfinae'd away and is just another flavor of
library defect

http://home.roadrunner.com/~hinnant/issue_review/lwg-defects.html#811

that can fall-back to the non-template form. Other than that, I
see no special win of the non-template constructor.

HTH & Greetings from Bremen,

Daniel Kr=FCgler


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Scott Meyers <NeverRead@aristeia.com>
Date: Wed, 11 Aug 2010 22:49:11 CST
Raw View
litb wrote:
>
> On 10 Aug., 04:14, Scott Meyers <NeverR...@aristeia.com> wrote:
>>
>> >From the FCD:
>>
>> template <class... Types>
>> class tuple {
>> public:
>>  ...
>>  explicit tuple(const Types&...);
>>  template <class... UTypes> explicit tuple(UTypes&&...);
>>  ...
>>
>> };
>>
>> Why do we need the first of these constructors?  The second one will
>> accept almost anything, and it permits rvalue arguments to be moved
>> into their corresponding tuple elements, while the first one will
>> require that such arguments be copied.
>>
>> The only thing I can see that the first constructor provides is
>> support for brace initialization syntax:
>>
>>  tuple<T1, T2, T3> t = { expr1, expr2, expr3 };    // calls 1st ctor above
>>
>> Is that all it gives us?
>>
>
> I think you wanted to do "t{ ... }" instead of "t = { ... }", because
> of the "explicit".

Right, thanks.

> But anyway, in fact, this is possible with the
>
> second constructor too. This is not triggering the non-deduced context
> thing, because this is list-initialization and it treats expr1, expr2
> and expr3 as separate arguments to the constructor(s) of tuple<>.

Right, duh.  But that makes the question even more relevant.  Why do
we need the first constructor at all?

Scott

--
* C++ and Beyond: Meyers, Sutter, & Alexandrescu, Oct. 24-27 near
Seattle (http://cppandbeyond.com/)
* License my training materials for commercial
(http://tinyurl.com/yfzvkp9) or personal use
(http://tinyurl.com/yl5ka5p).

[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: litb <Schaub-Johannes@web.de>
Date: Fri, 13 Aug 2010 11:56:24 CST
Raw View
On 10 Aug., 04:14, Scott Meyers <NeverR...@aristeia.com> wrote:
> >From the FCD:
>
> template <class... Types>
> class tuple {
> public:
>  ...
>  explicit tuple(const Types&...);
>  template <class... UTypes> explicit tuple(UTypes&&...);
>  ...
>
> };
>
> Why do we need the first of these constructors?  The second one will
> accept almost anything, and it permits rvalue arguments to be moved
> into their corresponding tuple elements, while the first one will
> require that such arguments be copied.
>

Now that i think about it again, consider this one:

struct A { A(initializer_list<int>); };
tuple<A> a{{1, 2}};

This needs the first constructor, because the second will have a non-
deduced context for the argument "{1, 2}".


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Scott Meyers <NeverRead@aristeia.com>
Date: Fri, 13 Aug 2010 11:57:11 CST
Raw View
=?ISO-8859-1?Q?Daniel_Kr=FCgler?= wrote:

> Ideally the template constructor should be constrained, see
>

I disagree.  I think it'd be better to get rid of the non-template
constructor and require that users pass nullptr if they want to initializer
a pointer.  This would not be practical for std::pair or for
std::tr1::tuple, but std::tuple is new to C++0x, so there is no existing
code base to break.

Scott

--
* C++ and Beyond: Meyers, Sutter, & Alexandrescu, Oct. 24-27 near Seattle
(http://cppandbeyond.com/)
* License my training materials for commercial (http://tinyurl.com/yfzvkp9)
or
personal use (http://tinyurl.com/yl5ka5p).

[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: Scott Meyers <NeverRead@aristeia.com>
Date: Mon, 9 Aug 2010 20:14:49 CST
Raw View
>From the FCD:

template <class... Types>
class tuple {
public:
 ...
 explicit tuple(const Types&...);
 template <class... UTypes> explicit tuple(UTypes&&...);
 ...
};

Why do we need the first of these constructors?  The second one will
accept almost anything, and it permits rvalue arguments to be moved
into their corresponding tuple elements, while the first one will
require that such arguments be copied.

The only thing I can see that the first constructor provides is
support for brace initialization syntax:

 tuple<T1, T2, T3> t = { expr1, expr2, expr3 };    // calls 1st ctor above

Is that all it gives us?

It's also my impression that the second constructor will be a better
match for any set of arguments except a set where all arguments are
const lvalues, provided the brace initialization syntax is not used:

 tuple<T1, T2, T3> t(expr1, expr2, expr3);    // calls 2nd ctor above unless
                                              // all exprs are const lvalues

Is that the case?

All clarification appreciated.

Thanks,

Scott

--
* C++ and Beyond: Meyers, Sutter, & Alexandrescu, Oct. 24-27 near
Seattle (http://cppandbeyond.com/)
* License my training materials for commercial
(http://tinyurl.com/yfzvkp9) or personal use
(http://tinyurl.com/yl5ka5p).

[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@netlab.cs.rpi.edu]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]





Author: litb <Schaub-Johannes@web.de>
Date: Tue, 10 Aug 2010 13:29:06 CST
Raw View
On 10 Aug., 04:14, Scott Meyers <NeverR...@aristeia.com> wrote:
> >From the FCD:
>
> template <class... Types>
> class tuple {
> public:
>  ...
>  explicit tuple(const Types&...);
>  template <class... UTypes> explicit tuple(UTypes&&...);
>  ...
>
> };
>
> Why do we need the first of these constructors?  The second one will
> accept almost anything, and it permits rvalue arguments to be moved
> into their corresponding tuple elements, while the first one will
> require that such arguments be copied.
>
> The only thing I can see that the first constructor provides is
> support for brace initialization syntax:
>
>  tuple<T1, T2, T3> t = { expr1, expr2, expr3 };    // calls 1st ctor above
>
> Is that all it gives us?
>

I think you wanted to do "t{ ... }" instead of "t = { ... }", because
of the "explicit". But anyway, in fact, this is possible with the
second constructor too. This is not triggering the non-deduced context
thing, because this is list-initialization and it treats expr1, expr2
and expr3 as separate arguments to the constructor(s) of tuple<>.


--
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use
mailto:std-c++@netlab.cs.rpi.edu<std-c%2B%2B@netlab.cs.rpi.edu>
]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html                      ]