From: Carl Barron on
In article
<howard.hinnant-BBDDCE.12010822112006(a)syrcnyrdrs-02-ge0.nyroc.rr.com>,
Howard Hinnant <howard.hinnant(a)gmail.com> wrote:

> In article <4qV8h.51940$uv5.351593(a)twister1.libero.it>,
> Alberto Ganesh Barbati <AlbertoBarbati(a)libero.it> wrote:
>
> > Terry G ha scritto:
> > >> Because back_inserter_iterator<> is an output iterator but not an input
> > >> iterator. value_type, which is defined as the type able to hold the
> > >> value of the expression *it, makes sense only for input iterators.
> > >
> > > What if I want to know what type *it will return?
> > >
> >
> > The requirement of an output iterator says that the expression "*it = v"
> > is well-defined and does what it's supposed to do, but it's not said
> > what the expression "*it" is required to be and even if it can be used
> > in any way different from "*it = v". Therefore, defining value_type to
> > be void is a big warning sign that you shouldn't rely on the actual
> > type. It's like this for your own good. Why do you want to know?
> >
> > Ganesh
> >
> > PS: once we have decltype in the language, we could write decltype(*it),
> > but the question remains: what for?
>
> I know why *I* want output iterators to have value_type. Because I want
> to write generic code like:
>
> template <class It>
> It
> format(char val, It first, It last)
> {
> typedef typename std::iterator_traits<It>::value_type value_type;
> if (first == last)
> throw format_error();
> *first = static_cast<value_type>(val);
> return ++first;
> }
>
> I.e. I don't want the return type of *it (which should be it::reference
> anyway, and it is fine with me if *it returns void). I want a type such
> that if I convert my value v to that type, I'm assured of a clean
> assignment into the output iterator.
>
> Note that I'm also wanting output iterators to be equality comparable.
> In the case of back_insert_iterator, the following definitions would be
> fine:
>
> bool operator==(const back_insert_iterator&,
> const back_insert_iterator&)
> {return false;}
>
> bool operator!=(const back_insert_iterator&,
> const back_insert_iterator&)
> {return true;}
>
> With such changes I could safely format a char into any "iterator
> delimited stream".
>
> template <class Container>
> class back_insert_iterator
> {
> protected:
> Container* container;
>
> public:
> typedef Container container_type;

well [N2134=06-0204 ]
24.4.2.1 Class template back_insert_iterator
namespace std {
template <class Container>
class back_insert_iterator :
public iterator<output_iterator_tag,void,void,void,void>
{
protected:
Container* container;
public:
typedef Container container_type;
// ,,,
};

template <class It,class Tag>
struct ValueType
{
typedef typename std::iterator_traits<It>::value_type type;
};

template <class It>
struct ValueType<It,std::input_iterator_tag>
{
typedef typename It::container_type::value_type type;
};

template <class It>
It format(char val,It first,It last)
{
typedef ValueType<It>::type value_type;
// ,,,
}

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Terry G on
Howard wrote:
> I know why *I* want output iterators to have value_type. Because I want
> to write generic code like:
>
> template <class It>
> It
> format(char val, It first, It last)
> {
> typedef typename std::iterator_traits<It>::value_type value_type;
> if (first == last)
> throw format_error();
> *first = static_cast<value_type>(val);
> return ++first;
> }
>
> I.e. I don't want the return type of *it (which should be it::reference
> anyway, and it is fine with me if *it returns void). I want a type such
> that if I convert my value v to that type, I'm assured of a clean
> assignment into the output iterator.
>
> Note that I'm also wanting output iterators to be equality comparable.
> In the case of back_insert_iterator, the following definitions would be
> fine: <snipped>

Exactly what I want, but you say it better.
I expected the value_type of the back_insert_iterator to be the value_type
of the associated container.
Actually, this is desirable for almost any output iterator, not just the
back_insert_iterator.
For some output iterators, value_type should be void when nothing else
makes
sense.
This seems intuitive to me.

A question: why do you prefer static_cast<value_type>(val)
instead of using the function-like form: value_type(val)?
Is there any significant difference?

terry



--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Gennaro Prota on
On 21 Nov 2006 17:17:16 -0500, Alberto Ganesh Barbati wrote:

>Because back_inserter_iterator<> is an output iterator but not an input
>iterator. value_type, which is defined as the type able to hold the
>value of the expression *it, makes sense only for input iterators.

In effect there was some uncertainty about this, clarified with
library issue 324. The documentation of the (brain-dead)
to_block_range() function of boost::dynamic_bitset<> should still be
fixed in this regard (though that's probably the smallest of
dynamic_bitset's problems).

--
Gennaro Prota
[To mail me, remove any 'u' from the provided address]

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Terry G on
Ganesh wrote:
>> Previously, I just returned a vector<MyType>, forcing a container, a
>> copy,
>> and a type.
>
> Previously? I'm sorry but I can't follow you there. You did not post any
> "previous" code to refer to. How could you expect people to understand?
>
>> I wanted to be more flexible, allowing the user to specify any
>> convertible
>> type, avoid an unnecessary copy,
>> and let her pick whatever container.
>
> Please provide us a *working* code snippet of what you have but you
> don't like and some (obviously not working, but hopefully clarifying)
> code of what you would like to have. Otherwise we (both you and I) are
> just losing our time.

Sorry, I've been guilty of that on several posts recently. I'm in a hurry.
Here's some runnable code that illustrates my point.
It contains my previous code, that used a vector<MyType>, where MyType is
uint8_t.
I wanted to allow the user to use the container of her choice and a
reasonable type too.
Thats the "current" version.
Then, I show the code that I wish would work, but it doesn't because
value_type for back_inserter is void.

Thanks for your help.
terry
======================================

#undef KLUDGE // Define this to make this program compile.

#include <vector>
#include <list>
#include <cstddef>
#include <iterator>
#include <algorithm>
#include <iostream>

using namespace std;

typedef unsigned char uint8_t;

typedef vector<uint8_t> MyType;
typedef vector<unsigned> UserType;

// Here's what I had before.

vector<MyType> CopyOut(const uint8_t* src, size_t size,
unsigned count)
{
vector<MyType> rval;
rval.reserve(count);
// Align values on 32-bit boundaries.
size_t stride = 4*((size+3)/4);
while (count--) {
rval.push_back(MyType(src, src+size));
src += stride;
}
return rval;
} // CopyOut

// Here's what I have now.

template <class T, class OutIter>
OutIter CopyOut(OutIter dst, const uint8_t* src, size_t size,
unsigned count)
{
// Align values on 32-bit boundaries.
size_t stride = 4*((size+3)/4);
while (count--) {
*dst++ = T(src, src+size);
src += stride;
}
return dst;
} // CopyOut

// Here's what I wish would work. Doesn't need T parameter.
template <class OutIter>
OutIter CopyOutWish(OutIter dst, const uint8_t* src, size_t size,
unsigned count)
{
#ifndef KLUDGE
// Oops! iterator_traits<OutIter>::value_type is 'void'.
typedef typename iterator_traits<OutIter>::value_type DstType;
#else
typedef UserType DstType;
#endif

// Align values on 32-bit boundaries.
size_t stride = 4*((size+3)/4);
while (count--) {
*dst++ = DstType(src, src+size);
src += stride;
}
return dst;
} // CopyOutWish

struct PseudoMemory {
uint8_t data[64];
PseudoMemory() {
for (int i=0; i!=sizeof(data); ++i)
data[i] = uint8_t(i);
} // ctor
}; // PseudoMemory;

PseudoMemory Memory;

void PrintMine(const MyType& x) {
copy(x.begin(), x.end(), ostream_iterator<unsigned>(cout, " "));
cout << endl;
} // PrintMine

void PrintUser(const UserType& x) {
copy(x.begin(), x.end(), ostream_iterator<unsigned>(cout, " "));
cout << endl;
} // PrintUser

int main() {
cout << endl << "Demonstrate previous method." << endl;
vector<MyType> myResult = CopyOut(&Memory.data[4], 3, 5);
for_each(myResult.begin(), myResult.end(), PrintMine);

cout << endl << "Demonstrate current method." << endl;
list<UserType> userResult;
(void) CopyOut<UserType>(back_inserter(userResult),
&Memory.data[4], 3, 5);
for_each(userResult.begin(), userResult.end(), PrintUser);

cout << endl << "Demonstrate wishful method." << endl;
userResult.clear();
(void) CopyOutWish(back_inserter(userResult),
&Memory.data[4], 3, 5);
for_each(userResult.begin(), userResult.end(), PrintUser);

return EXIT_SUCCESS;
} // main



--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

From: Alberto Ganesh Barbati on
Terry G ha scritto:
>
> A question: why do you prefer static_cast<value_type>(val)
> instead of using the function-like form: value_type(val)?
> Is there any significant difference?
>

The function-like form with one argument is actually equivalent to the
C-style cast (value_type)(val) so it could apply either a static_cast or
a reinterpret_cast (plus an additional const_cast).

Ganesh

--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]

First  |  Prev  |  Next  |  Last
Pages: 1 2 3 4 5 6
Prev: The D Programming Language
Next: CRTP question