From: ShaunJ on
Hi,

The value_type of an output iterator is defined to be void, and there
seems to be a good reason for this. How should I modify the following
code without having to make value_type a template parameter of
make_pairs?

Thanks,
Shaun

#include <iostream>
#include <iterator>

using namespace std;

struct pair_strings {
const char *a, *b;
pair_strings(const char* a, const char* b) : a(a), b(b) { }
friend ostream& operator <<(ostream& out, const pair_strings& o)
{
return out << o.a << '\t' << o.b;
}
};

template <typename It0, typename It1, typename OutIt>
OutIt make_pairs(It0 first0, It0 last0, It1 first1, OutIt out)
{
#if does_not_work
typedef typename iterator_traits<OutIt>::value_type value_type;
#else
typedef pair_strings value_type;
#endif
while (first0 != last0)
*out++ = value_type(*first0++, *first1++);
return out;
}

int main(int argc, const char** argv)
{
make_pairs(argv, argv+argc/2, argv+argc/2,
ostream_iterator<pair_strings>(cout, "\n"));
return 0;
}

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

From: ShaunJ on
On Jul 30, 12:50 pm, ShaunJ <sjack...(a)gmail.com> wrote:
> Hi,
>
> The value_type of an output iterator is defined to be void, and there
> seems to be a good reason for this. How should I modify the following
> code without having to make value_type a template parameter of
> make_pairs?
>
> Thanks,
> Shaun

The same functionality can be accomplished using the algorithm
transform, but I'm still curious to know if it can be accomplished
without needing to pass the transformation function to the algorithm.

#include <algorithm>
#include <iostream>
#include <iterator>

using namespace std;

struct pair_strings {
const char *a, *b;
pair_strings(const char* a, const char* b) : a(a), b(b) { }
static pair_strings create(const char* a, const char* b)
{
return pair_strings(a, b);
}
friend ostream& operator <<(ostream& out, const pair_strings& o)
{
return out << o.a << '\t' << o.b;
}
};

int main(int argc, const char** argv)
{
transform(argv, argv+argc/2, argv+argc/2,
ostream_iterator<pair_strings>(cout, "\n"),
pair_strings::create);
return 0;
}


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

From: Daniel Krügler on
On 30 Jul., 21:50, ShaunJ <sjack...(a)gmail.com> wrote:
> Hi,
>
> The value_type of an output iterator is defined to be void, and there
> seems to be a good reason for this. How should I modify the following
> code without having to make value_type a template parameter of
> make_pairs?

Let me try to sketch the situation in form of a
dialogue:

You: "Just gimme something!"
OutputStream: "What do you want?"
You: "It doesn't matter - just something!"
Outputstream: "Sorry, I don't know how to
answer this question"

Joke aside: A *general* (or "pure") output
iterator does not have a fixed value type.
If this is true, you cannot require the
output stream to provide you one.

There is another way of looking at the problem:
Why does the function have the name "make_pairs"?
I assume, the name has some meaning. So, either
you have a concrete idea of the meaning or you
don't.

a) If you have an idea, you should use it, i.e.
require some special type or factory function.

b) If you don't have any idea, why don't you
use a heterogeneous container that fits
everything?

For (b), there is no reason for value_type. You could
just use std::make_pair (or std::make_tuple) as follows:

template <typename It0, typename It1, typename OutIt>
OutIt make_pairs(It0 first0, It0 last0, It1 first1, OutIt out)
{
while (first0 != last0)
*out++ = std::make_pair(*first0++, *first1++);
return out;
}

Of-course this means that out contains now std::pair<T, U>,
where T and U are the value types of It0 and It1. If this
doesn't fit your purpose, you should either

- Specify the intermediate output type (An idea that you
excluded)
- Impose requirements on the type OutIt that allows to
retrieve the value type. You could for example define
a separate traits type, that can be specialized by used
code. If you want, you could partially specialize the
traits for std::ostream_iterator to deduce the type T
(see below).

What I would agree with is, that it seems to be a reasonable
suggestion that std::ostream_iterator *does* provide the type
for you. Since it does not yet, try the traits approach, e.g.

template<class OutIter>
struct output_iterator_traits {
typedef typename OutIter::value_type value_type;
// ...
};

template<class T, class charT, class traits>
struct output_iterator_traits<std::ostream_iterator<T, charT, traits>
> {
typedef T value_type;
// ...
};

HTH & Greetings from Bremen,

Daniel Kr�gler


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

From: ShaunJ on
Hi Daniel,

On Jul 30, 6:14 pm, Daniel Kr�gler <daniel.krueg...(a)googlemail.com>
wrote:
> On 30 Jul., 21:50, ShaunJ <sjack...(a)gmail.com> wrote:
>
> > Hi,
>
> > The value_type of an output iterator is defined to be void, and there
> > seems to be a good reason for this. How should I modify the following
> > code without having to make value_type a template parameter of
> > make_pairs?
>
> Let me try to sketch the situation in form of a
> dialogue:
>
> You: "Just gimme something!"
> OutputStream: "What do you want?"
> You: "It doesn't matter - just something!"
> Outputstream: "Sorry, I don't know how to
> answer this question"
>
> Joke aside: A *general* (or "pure") output
> iterator does not have a fixed value type.
> If this is true, you cannot require the
> output stream to provide you one.

Most output iterators would have a sensible type for value_type, e.g.
the type held by the collection over which they iterate. These
iterators I feel should define value_type to that sensible type. If
the output iterator truly is general and can take arbitrary types,
then sure, value_type should be void.

> There is another way of looking at the problem:
> Why does the function have the name "make_pairs"?
> I assume, the name has some meaning. So, either
> you have a concrete idea of the meaning or you
> don't.
>
> a) If you have an idea, you should use it, i.e.
> require some special type or factory function.

A reasonable solution and parallels std::transform.

> b) If you don't have any idea, why don't you
> use a heterogeneous container that fits
> everything?
>
> For (b), there is no reason for value_type. You could
> just use std::make_pair (or std::make_tuple) as follows:
>
> template <typename It0, typename It1, typename OutIt>
> OutIt make_pairs(It0 first0, It0 last0, It1 first1, OutIt out)
> {
> while (first0 != last0)
> *out++ = std::make_pair(*first0++, *first1++);
> return out;
> }

This doesn't fit my purpose because I would like to define operator<<
for this type (so that it can be used with ostream_iterator), which
isn't possible (cleanly) for std::pair. That being said, I feel the
algorithm should also be able to work with std::pair (because, why
shouldn't it?).

> Of-course this means that out contains now std::pair<T, U>,
> where T and U are the value types of It0 and It1. If this
> doesn't fit your purpose, you should either
>
> - Specify the intermediate output type (An idea that you
> excluded)

A reasonable solution. I was interested to learn whether specifying
the output type was strictly necessary, when it seems the output
iterator should know the type it expects and should be able to
communicate this information to the algorithm.

> - Impose requirements on the type OutIt that allows to
> retrieve the value type. You could for example define
> a separate traits type, that can be specialized by used
> code. If you want, you could partially specialize the
> traits for std::ostream_iterator to deduce the type T
> (see below).
>
> What I would agree with is, that it seems to be a reasonable
> suggestion that std::ostream_iterator *does* provide the type
> for you. Since it does not yet, try the traits approach, e.g.
[code clipped]

The traits approach worked perfectly. Thanks for your help, Daniel.

Cheers,
Shaun


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