C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

Defect Report: tuple::tail() should be in the public interfa

 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ language, library and standards
View previous topic :: View next topic  
Author Message
Joe Gottman
Guest





PostPosted: Mon May 21, 2007 2:20 am    Post subject: Defect Report: tuple::tail() should be in the public interfa Reply with quote



As std::tuple is currently written, it is difficult to impossible to
write functions that take a tuple of indeterminate size as a parameter
and make use of the entire tuple. For example, consider a function that
writes the contents of a tuple to a stream.

template <class... Types>
inline ostream &print_tuple(ostream &os, const tuple<Types...> &tup);

It is impossible to use a for-loop and tuple::get to write this
function, because tuple::get<N> requires N to be a compile-time constant
while a for-loop requires N to be a variable. The programmer would have
to write an implementation function templated on an int and the Types:
template <int N, class...Types>
ostream &print_tuple_imp(ostream &os, const tuple<Types...> &tup);

This is overly burdensome for the average programmer, especially since
the rules of templates require that N be declared first in the template
list, where it cannot mention the parameter pack Types... . If
tuple::tail() were available in the public interface, the implementation
function would not be necessary:

// Default implementation
template <class ... Types>
ostream &print_tuple(ostream &os, const tuple<Types ...> &tup)
{
os << get<0>(tup) << " ";
return print_tuple(os, tup.tail());
}

//overload for tuple<>
inline ostream &print_tuple(ostream &os, const tuple<> &tup)
{
return os; // Nothing to do with an empty tuple;
}

Note that the definition of operator <() on tuples already uses the
tail() function, even though it is careful not to name it as such.

Another simple function on tuples that is difficult to write as tuple is
currently defined is a function that concatenates two tuples

template <class ...Types1, class ... Types2>
inline tuple<Types1..., Types2...>
concatenate(const tuple<Types1...> &tup1, const tuple<Types2...> &tup2);

Thus, if tup1 is a tuple<int, string> constaining {1, "Hello"} and tup2
is a tuple <int, double, char> containing {1, 2.0, '3'}, then
concatenate(tup1, tup2) would be a tuple<int, string, int, double, char>
containing {1, "Hello", 1, 2.0, '3'}. It is very useful and elementary
to concatenate two tuples, but as tuples are written now it would be
very difficult to implement this function, even using an implementation
function templated on int. In order to implement this, it would be
useful to add two templated constructors to tuple. The first is a
constructor that takes a scalar object and a tuple of size one less than
the size of the tuple we are constructing. It would initialize the head
of the tuple with the scalar object and the tail with the tuple. Using
this constructor and constructor forwarding, it is possible to define a
constructor that takes two tuples such that the sum of their sizes
equals the size of the tuple we are constructing.

Finally, even though it is not strictly necessary, it is probably a good
idea to define a head() member function for tuples that returns get<0>,
simply to aid in programmer understanding of the tail() function.

Proposed Resolution:

Change 20.3.1 as follows:
add the following public typedefs and member functions to tuple:

typedef tuple_element<0, tuple> head_type; // iff sizeof...(Types) > 0
typedef tuple<TailTypes...> tail_type; // iff sizeof...(Types) > 0,
where TailTypes... is a parameter pack containing all the types in
Types... except the first.

head_type &head();//iff sizeof...(Types) > 0
const head_type &head() const; //iff sizeof...(Types) > 0

tail_type &tail(); // iff sizeof...(Types) > 0
const tail_type &tail() const; // iff sizeof...(Types) > 0

template <class U, typename... UTypes>
tuple(U &&u, const tuple<UTypes...> &tup); // iff sizeof...(Types) ==
sizeof...(UTypes) + 1

template <class U, typename... UTypes>
tuple(U &&u, tuple<UTypes...> &&tup); // iff sizeof...(Types) ==
sizeof...(UTypes) + 1

template <class UTypes..., class VTypes...>
tuple(const tuple<UTypes> &tup1, const tuple<VTypes> &tup2); // iff
sizeof...(Types) == sizeof...(UTypes) + sizeof...(VTypes)

template <class UTypes..., class VTypes...>
tuple(const tuple<UTypes> &tup1, tuple<VTypes> &&tup2); // iff
sizeof...(Types) == sizeof...(UTypes) + sizeof...(VTypes)

template <class UTypes..., class VTypes...>
tuple(tuple<UTypes> &&tup1, const tuple<VTypes> &tup2); // iff
sizeof...(Types) == sizeof...(UTypes) + sizeof...(VTypes)

template <class UTypes..., class VTypes...>
tuple(tuple<UTypes> &&tup1, tuple<VTypes> &&tup2); // iff
sizeof...(Types) == sizeof...(UTypes) + sizeof...(VTypes)


Add the following definitions to 20.3.1.1:


template <class U, typename... UTypes>
tuple(U &&u, tuple<UTypes...> &&tup);

1) Requires: sizeof...(Types) == sizeof...(UTypes) + 1, U is convertible
to head_type, tuple<UTypes> is convertible to tail_type
2) Effects: constructs head() with forward<U>(u) and tail() with tup

template <class UTypes..., class VTypes...>
tuple(const tuple<UTypes> &tup1, const tuple<VTypes> &tup2); // iff
sizeof...(Types) == sizeof...(UTypes) + sizeof...(VTypes)

1) Requires: sizeof...(Types) == sizeof...(UTypes) + 1, U is convertible
to head_type, tuple<UTypes> is convertible to tail_type
2) Effects: constructs head() with forward<U>(u) and tail() with move(tup)

template <class UTypes..., class VTypes...>
tuple(const tuple<UTypes> &tup1, tuple<VTypes> &&tup2);
1) Requires: sizeof...(Types) == sizeof...(UTypes) + sizeof...(VTypes),
The first sizeof...(UTypes) parameters in Types are constructable
from the corresponding elements in UTypes, and the rest are
constructable from the corresponding elements in VTypes
2) Effects: If sizeof...(UTypes) == 0, constructs the tuple from tup2.
Otherwise, constructs head() from tup1.head() and tail() from
tup1.tail() and tup2.


template <class UTypes..., class VTypes...>
tuple(tuple<UTypes> &&tup1, const tuple<VTypes> &tup2);
1) Requires: sizeof...(Types) == sizeof...(UTypes) + sizeof...(VTypes),
The first sizeof...(UTypes) parameters in Types are constructable
from the corresponding elements in UTypes, and the rest are
constructable from the corresponding elements in VTypes
2) Effects: If sizeof...(UTypes) == 0, constructs the tuple from tup2.
Otherwise, constructs head() from move(tup1.head()) and tail() from
move(tup1.tail()) and tup2.


template <class UTypes..., class VTypes...>
tuple(const tuple<UTypes> &tup1, tuple<VTypes> &&tup2);
1) Requires: sizeof...(Types) == sizeof...(UTypes) + sizeof...(VTypes),
The first sizeof...(UTypes) parameters in Types are constructable
from the corresponding elements in UTypes, and the rest are
constructable from the corresponding elements in VTypes
2) Effects: If sizeof...(UTypes) == 0, constructs the tuple from
move(tup2). Otherwise, constructs head() from tup1.head() and tail()
from move(tup1.tail() and move(tup2).

template <class UTypes..., class VTypes...>
tuple(tuple<UTypes> &&tup1, tuple<VTypes> &&tup2); // iff
sizeof...(Types) == sizeof...(UTypes) + sizeof...(VTypes)
1) Requires: sizeof...(Types) == sizeof...(UTypes) + sizeof...(VTypes),
The first sizeof...(UTypes) parameters in Types are constructable
from the corresponding elements in UTypes, and the rest are
constructable from the corresponding elements in VTypes
2) Effects: If sizeof...(UTypes) == 0, constructs the tuple from
move(tup2). Otherwise, constructs head() from move(tup1.head()) and
tail() from move(tup1.tail()) and move(tup2).


Add a section for tuple access functions:

head_type &head()
const head_type &head() const

1) Requires: sizeof...(Types) > 0
2) Returns: get<0>(*this)

tail_type &tail()
const tail_type &tail() const;

1) Requires: sizeof...(Types) > 0
2) Returns: A reference to a tuple consisting of all the elements of
*this except the first.

[Note: No elements are copied and no copy constructor is called]

Change the definition of tuple::operator<() in section 20.3.1.4 so that
the returns clause reads:

Returns: The result of a lexicographical comparison between t and u. The
result is defined as: (bool)(get<0>(t)
< get<0>(u)) || (!(bool)(get<0>(u) < get<0>(t)) && u.tail() < v.tail()).
For any two zero-length tuples e and f, e < f returns false.




Joe Gottman

---
[ 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 ]
Back to top
Carl Barron
Guest





PostPosted: Mon May 21, 2007 6:38 am    Post subject: Re: Defect Report: tuple::tail() should be in the public int Reply with quote



Joe Gottman <jgottman (AT) carolina (DOT) rr.com> wrote:

Quote:
As std::tuple is currently written, it is difficult to impossible to
write functions that take a tuple of indeterminate size as a parameter
and make use of the entire tuple. For example, consider a function that
writes the contents of a tuple to a stream.

template <class... Types
inline ostream &print_tuple(ostream &os, const tuple<Types...> &tup);

It is impossible to use a for-loop and tuple::get to write this
function, because tuple::get<N> requires N to be a compile-time constant
while a for-loop requires N to be a variable. The programmer would have
to write an implementation function templated on an int and the Types:

gee some simple template programming does this assuming an

std::ostream & operator << (std::ostream &,const T &); exists
for each type in the tuple.

template <int N,int M, class T>
struct printer_unit
{
static std::ostream do_it(std::ostream &os,const T &t)
{
os << std::tr1::get<N>(t);
return printer_unit<N+1,M,T>::do_it(os,t);
}
};

template <int N,class T>
struct printer_unit<N,N,T>
{
static std::ostream & do_it(std::ostream &os,const T &t)
{
return os;
}
};

template <class T>
inline
std::ostream & print_tuple(std::ostream &os,const T &t)
{
return printer_unit
<
0,
std::tr1::tuple_size<T>::value,
T
Quote:
::do_it(os,t);
}


and no copies of the tuple are needed. A similiar approach can handle
other iteration of a tuple.

A general approach is to construct an mpl sequence from tuple_size<> and
tuple_element<> and creating a boost::variant from that sequence. You
could convert the tuple to an stl::container of the variant type and
just use ordinary algorithms, providing a functor that handles all types
passed. or just do above and pass get<N>(t) to the functor/function
like above.

---
[ 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 ]
Back to top
Joe Gottman
Guest





PostPosted: Mon May 21, 2007 5:47 pm    Post subject: Re: Defect Report: tuple::tail() should be in the public int Reply with quote



Carl Barron wrote:


Quote:
gee some simple template programming does this assuming an
std::ostream & operator << (std::ostream &,const T &); exists
for each type in the tuple.

template <int N,int M, class T
struct printer_unit
{
static std::ostream do_it(std::ostream &os,const T &t)
{
os << std::tr1::get<N>(t);
return printer_unit<N+1,M,T>::do_it(os,t);
}
};

template <int N,class T
struct printer_unit<N,N,T
{
static std::ostream & do_it(std::ostream &os,const T &t)
{
return os;
}
};

template <class T
inline
std::ostream & print_tuple(std::ostream &os,const T &t)
{
return printer_unit

0,
std::tr1::tuple_size<T>::value,
T
::do_it(os,t);
}

and no copies of the tuple are needed. A similiar approach can handle
other iteration of a tuple.

A general approach is to construct an mpl sequence from tuple_size<> and
tuple_element<> and creating a boost::variant from that sequence. You
could convert the tuple to an stl::container of the variant type and
just use ordinary algorithms, providing a functor that handles all types
passed. or just do above and pass get<N>(t) to the functor/function
like above.


I agree that this is will work, but this is a heck of a lot of
machinery to require just to print out a tuple. Also, it is not
reusable, so clients would have to repeat the pattern to do something
else with the entire tuple. And as for copying, in every implementation
of tuple I have seen a tuple<X, Y, Z> contains an object of tuple<Y, Z>
internally, either by inheritance or as a member element, so there
should not be any copying necessary in the implementation of tail().

Joe Gottman

---
[ 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 ]
Back to top
Douglas Gregor
Guest





PostPosted: Mon May 21, 2007 5:48 pm    Post subject: Re: Defect Report: tuple::tail() should be in the public int Reply with quote

On May 20, 5:20 pm, jgott...@carolina.rr.com (Joe Gottman) wrote:
Quote:
As std::tuple is currently written, it is difficult to impossible to
write functions that take a tuple of indeterminate size as a parameter
and make use of the entire tuple. For example, consider a function that
writes the contents of a tuple to a stream.

template <class... Types
inline ostream &print_tuple(ostream &os, const tuple<Types...> &tup);

It is impossible to use a for-loop and tuple::get to write this
function, because tuple::get<N> requires N to be a compile-time constant
while a for-loop requires N to be a variable.

Right. When dealing with tuples, you're going to be doing some
metaprogramming. Without adding some kind of direct metaprogramming
support into the language, I don't think this will change.

Quote:
The programmer would have
to write an implementation function templated on an int and the Types:
template <int N, class...Types
ostream &print_tuple_imp(ostream &os, const tuple<Types...> &tup);

This is overly burdensome for the average programmer, especially since
the rules of templates require that N be declared first in the template
list, where it cannot mention the parameter pack Types... .

Well, you could use a defaulted template argument to get I:

template <int I = 0, class... Types>
inline ostream &print_tuple(ostream &os, const tuple<Types...>
&tup);

Still metaprogramming, and you'll still need a basis case, but at
least there's no helper function.

Quote:
Note that the definition of operator <() on tuples already uses the
tail() function, even though it is careful not to name it as such.

Which definition? Implementers are free to define tuple however they
want. In fact, one of my favorite implementations of tuple doesn't
have an explicit "tail". It ends up with "tuple" inheriting from N
base classes tuple_value<0, T0>, tuple_value<1, T1>, tuple_value<2,
T2>, ..., tuple_value<N-1, TN-1>, all as peers. In this case, there is
no tail, because the inheritance hierarchy is very wide (but only 1
level deep).

Quote:
Another simple function on tuples that is difficult to write as tuple is
currently defined is a function that concatenates two tuples

template <class ...Types1, class ... Types2
inline tuple<Types1..., Types2...
concatenate(const tuple<Types1...> &tup1, const tuple<Types2...> &tup2);

Yep, that's difficult to write.

Quote:
useful to add two templated constructors to tuple. The first is a
constructor that takes a scalar object and a tuple of size one less than
the size of the tuple we are constructing. It would initialize the head
of the tuple with the scalar object and the tail with the tuple. Using
this constructor and constructor forwarding, it is possible to define a
constructor that takes two tuples such that the sum of their sizes
equals the size of the tuple we are constructing.

This is a neat idea. I'm a bit concerned about ambiguities... if one
does this, for example, what happens?

tuple<tuple<int>, tuple<float>> t(make_tuple(17l),
make_tuple(3.14159));

There are other such ambiguities when the tuple contains tuples.

Quote:
Finally, even though it is not strictly necessary, it is probably a good
idea to define a head() member function for tuples that returns get<0>,
simply to aid in programmer understanding of the tail() function.

I don't agree with the addition of tail(), because it puts too many
restrictions on implementers and makes it impossible to use a
particularly good implementation technique. So, head() shouldn't be
there either.

These constructors...

Quote:
template <class U, typename... UTypes
tuple(U &&u, const tuple<UTypes...> &tup); // iff sizeof...(Types) ==
sizeof...(UTypes) + 1

template <class U, typename... UTypes
tuple(U &&u, tuple<UTypes...> &&tup); // iff sizeof...(Types) ==
sizeof...(UTypes) + 1

are just a special case of these constructors, right?

Quote:
template <class UTypes..., class VTypes...
tuple(const tuple<UTypes> &tup1, const tuple<VTypes> &tup2); // iff
sizeof...(Types) == sizeof...(UTypes) + sizeof...(VTypes)

template <class UTypes..., class VTypes...
tuple(const tuple<UTypes> &tup1, tuple<VTypes> &&tup2); // iff
sizeof...(Types) == sizeof...(UTypes) + sizeof...(VTypes)

template <class UTypes..., class VTypes...
tuple(tuple<UTypes> &&tup1, const tuple<VTypes> &tup2); // iff
sizeof...(Types) == sizeof...(UTypes) + sizeof...(VTypes)

template <class UTypes..., class VTypes...
tuple(tuple<UTypes> &&tup1, tuple<VTypes> &&tup2); // iff
sizeof...(Types) == sizeof...(UTypes) + sizeof...(VTypes)

If so, do we really need the former (U, tuple<UTypes...>)
constructors?

Anyway, I really like the concatenating constructors. They fill a real
need and make a lot of sense. But head/tail put too many restrictions
on implementers, and aren't really necessary, so I think we should
skip those.

To make this happen for C++0x, I suggest that you turn your post into
a short paper for the C++ committee. Include rationale, a discussion
of the ambiguity issue I mentioned above (including how to (re)solve
it!), and the proposed wording you already gave. Assuming they can
find the time, I think the Library Working Group will agree with this
change.

- Doug

---
[ 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 ]
Back to top
Carl Barron
Guest





PostPosted: Tue May 22, 2007 3:51 am    Post subject: Re: Defect Report: tuple::tail() should be in the public int Reply with quote

In article <46517ea1$0$15148$4c368faf (AT) roadrunner (DOT) com>, Joe Gottman
<jgottman (AT) carolina (DOT) rr.com> wrote:
\
Quote:
A general approach is to construct an mpl sequence from tuple_size<> and
tuple_element<> and creating a boost::variant from that sequence. You
could convert the tuple to an stl::container of the variant type and
just use ordinary algorithms, providing a functor that handles all types
passed. or just do above and pass get<N>(t) to the functor/function
like above.


I agree that this is will work, but this is a heck of a lot of
machinery to require just to print out a tuple. Also, it is not
reusable, so clients would have to repeat the pattern to do something
else with the entire tuple. And as for copying, in every implementation
of tuple I have seen a tuple<X, Y, Z> contains an object of tuple<Y, Z
internally, either by inheritance or as a member element, so there
should not be any copying necessary in the implementation of tail().

TR1 and n2134.pdf do not require a lisp like structure for

std::tr1::tuple<T1,...TN>. As such I do not see a defect.

The example is not written to be a library component. It is possible to
write the unit classes to have a functor template parameter and call
that functor with the result of tr1::get<N>(), in a similiar approach
further its not that complicated an algorithm.

for about 100 lines of code you can provide a tuple_view of the tuple
using boost::mpl then mpl::for_each() can handle any functor that
handles all the distinct types of your tuple.

boost::fusion is a possible replacement, but it is not widely known or
used at this time.

---
[ 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 ]
Back to top
Joe Gottman
Guest





PostPosted: Tue May 22, 2007 4:33 am    Post subject: Re: Defect Report: tuple::tail() should be in the public int Reply with quote

Douglas Gregor wrote:
Quote:
On May 20, 5:20 pm, jgott...@carolina.rr.com (Joe Gottman) wrote:

Note that the definition of operator <() on tuples already uses the
tail() function, even though it is careful not to name it as such.

Which definition? Implementers are free to define tuple however they
want. In fact, one of my favorite implementations of tuple doesn't
have an explicit "tail". It ends up with "tuple" inheriting from N
base classes tuple_value<0, T0>, tuple_value<1, T1>, tuple_value<2,
T2>, ..., tuple_value<N-1, TN-1>, all as peers. In this case, there is
no tail, because the inheritance hierarchy is very wide (but only 1
level deep).


The current working paper says the following in the definition of
tuple::operator<()

Returns: The result of a lexicographical comparison between t and u
The result is defined as: (bool)(get<0>(t)< get<0>(u)) ||
(!(bool)(get<0>(u) < get<0>(t)) && ttail < utail), where rtail for some
tuple r is a
tuple containing all but the first element of r. For any two zero-length
tuples e and f, e < f returns false.


I didn't realize you could do the inheritance with the multiple
tuple_value<X, N>. Given that, it looks like there's no way to implement
a tail() function without unduly restricting implementation.

Quote:
Another simple function on tuples that is difficult to write as tuple is
currently defined is a function that concatenates two tuples

template <class ...Types1, class ... Types2
inline tuple<Types1..., Types2...
concatenate(const tuple<Types1...> &tup1, const tuple<Types2...> &tup2);

Yep, that's difficult to write.

useful to add two templated constructors to tuple. The first is a
constructor that takes a scalar object and a tuple of size one less than
the size of the tuple we are constructing. It would initialize the head
of the tuple with the scalar object and the tail with the tuple. Using
this constructor and constructor forwarding, it is possible to define a
constructor that takes two tuples such that the sum of their sizes
equals the size of the tuple we are constructing.

This is a neat idea. I'm a bit concerned about ambiguities... if one
does this, for example, what happens?

tuple<tuple<int>, tuple<float>> t(make_tuple(17l),
make_tuple(3.14159));

You end up with tuple<tuple<int>, tuple<float>>. make_tuple<X, Y>
unambiguously creates an object of type tuple<X, Y>.
Quote:

There are other such ambiguities when the tuple contains tuples.

Finally, even though it is not strictly necessary, it is probably a good
idea to define a head() member function for tuples that returns get<0>,
simply to aid in programmer understanding of the tail() function.

I don't agree with the addition of tail(), because it puts too many
restrictions on implementers and makes it impossible to use a
particularly good implementation technique. So, head() shouldn't be
there either.

These constructors...

template <class U, typename... UTypes
tuple(U &&u, const tuple<UTypes...> &tup); // iff sizeof...(Types) ==
sizeof...(UTypes) + 1

template <class U, typename... UTypes
tuple(U &&u, tuple<UTypes...> &&tup); // iff sizeof...(Types) ==
sizeof...(UTypes) + 1

are just a special case of these constructors, right?

template <class UTypes..., class VTypes...
tuple(const tuple<UTypes> &tup1, const tuple<VTypes> &tup2); // iff
sizeof...(Types) == sizeof...(UTypes) + sizeof...(VTypes)

template <class UTypes..., class VTypes...
tuple(const tuple<UTypes> &tup1, tuple<VTypes> &&tup2); // iff
sizeof...(Types) == sizeof...(UTypes) + sizeof...(VTypes)

template <class UTypes..., class VTypes...
tuple(tuple<UTypes> &&tup1, const tuple<VTypes> &tup2); // iff
sizeof...(Types) == sizeof...(UTypes) + sizeof...(VTypes)

template <class UTypes..., class VTypes...
tuple(tuple<UTypes> &&tup1, tuple<VTypes> &&tup2); // iff
sizeof...(Types) == sizeof...(UTypes) + sizeof...(VTypes)

If so, do we really need the former (U, tuple<UTypes...>)
constructors?

Anyway, I really like the concatenating constructors. They fill a real
need and make a lot of sense. But head/tail put too many restrictions
on implementers, and aren't really necessary, so I think we should
skip those.

To make this happen for C++0x, I suggest that you turn your post into
a short paper for the C++ committee. Include rationale, a discussion
of the ambiguity issue I mentioned above (including how to (re)solve
it!), and the proposed wording you already gave. Assuming they can
find the time, I think the Library Working Group will agree with this
change.


Thanks. Do you think it would be a good idea to define
concatenation as a tuple::operator+() function? It would be similar to
std::string::operator+() and very useful when used in conjunction with
an auto-declared variable.

Joe Gottman

---
[ 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 ]
Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ language, library and standards All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.