Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C++ (http://www.velocityreviews.com/forums/f39-c.html)
-   -   output_iterator_tag and back_insert_iterator (http://www.velocityreviews.com/forums/t621463-output_iterator_tag-and-back_insert_iterator.html)

Rares Vernica 06-21-2008 01:50 AM

output_iterator_tag and back_insert_iterator
 
Hello,

I am trying to write a generic function that can read data from a file
and store it in a container.

I defined the following function:

template<class T>
void readBinaryFile(
const std::string &filename,
std::iterator<std::output_iterator_tag, T> data)
{
....
}

Because the function is reading binary data, it needs to know the type of
the elements in the container, T.

When I call it with something like:

vector<float> f;
readBinaryFile<float>("test.bin", back_inserter(f));

I get:

error: no matching function for call to ‘readBinaryFile(std::string&,
std::back_insert_iterator<std::vector<float, std::allocator<float> > >)’

I am a little bit confused because I know that the back_insert_iterator
is an output iterator. In fact, back_insert_iterator is defined as:

template<typename _Container>
class back_insert_iterator
: public iterator<output_iterator_tag, void, void, void, void>

If I change the function declaration to:

template<class T, class OutputIterator>
void readBinaryFile(
const std::string &filename,
OutputIterator data)

it works fine.

If possible, I would prefer to make the first declaration work
somehow. Or at least, understand why it does not work.

Thanks,
Rares


Kai-Uwe Bux 06-21-2008 02:13 AM

Re: output_iterator_tag and back_insert_iterator
 
Rares Vernica wrote:

> Hello,
>
> I am trying to write a generic function that can read data from a file
> and store it in a container.
>
> I defined the following function:
>
> template<class T>
> void readBinaryFile(
> const std::string &filename,
> std::iterator<std::output_iterator_tag, T> data)
> {
> ...
> }


You probably don't want that signature:

(a) When you pass an iterator, it will be sliced down to std::iterator,
which is a rather meaningless thing.

(b) Even if you fix that (e.g., passing the iterator by reference), you
would limit the use of your function to iterator types derived from
std::iterator< output_iterator_tag, T >. There are not that many.

You should consider:

template < typename T, typename InIter >
void readBinaryFile(
std::string const & filename,
InIter where ) {
....
}

which is much more versatile.


> Because the function is reading binary data, it needs to know the type of
> the elements in the container, T.
>
> When I call it with something like:
>
> vector<float> f;
> readBinaryFile<float>("test.bin", back_inserter(f));
>
> I get:
>
> error: no matching function for call to ?readBinaryFile(std::string&,
> std::back_insert_iterator<std::vector<float, std::allocator<float> > >)?
>
> I am a little bit confused because I know that the back_insert_iterator
> is an output iterator. In fact, back_insert_iterator is defined as:
>
> template<typename _Container>
> class back_insert_iterator
> : public iterator<output_iterator_tag, void, void, void, void>


Note that float != void. You would want that back_inserter to be derived
from iterator< output_iterator_tag, float >, but that is _not_ what it is.

> If I change the function declaration to:
>
> template<class T, class OutputIterator>
> void readBinaryFile(
> const std::string &filename,
> OutputIterator data)
>
> it works fine.


Aha.

> If possible, I would prefer to make the first declaration work
> somehow.


No, you would not :-)

> Or at least, understand why it does not work.


See above.


Best

Kai-Uwe Bux

Jerry Coffin 06-21-2008 06:06 AM

Re: output_iterator_tag and back_insert_iterator
 
In article <y1rzlpfeeur.fsf@ics.uci.edu>, rares@ics.uci.edu says...

[ ... ]

> I defined the following function:
>
> template<class T>
> void readBinaryFile(
> const std::string &filename,
> std::iterator<std::output_iterator_tag, T> data)
> {
> ...
> }


That was your first mistake... :-)

> Because the function is reading binary data, it needs to know the type of
> the elements in the container, T.


Yup.

The function want is already implemented. It's called std::copy.

All you need to do is write an extractor that extracts an item from your
file correctly. The one problem is that there are already overloads to
read the data incorrectly (i.e. from a text file) for many built-in
types. You can overcome this by creating a proxy class, something like:

template <class T>
class binIO {
T data;
public:
operator T() const { return data; }

binIO(T value = T()) : data(value) { }

friend std::istream &operator>>(std::istream &is, binIO &f) {
return is.read((char *)&f.data, sizeof(f.data));
}
friend std::ostream &operator<<(std::ostream &os, binIO const &f) {
return os.write((char *)&f.data, sizeof(f.data));
}
};

To read (for example) a file of floats in binary format into a vector,
you'd do something like:

std::vector<float> data;
std::ifstream in("input.dat", std::ios::binary);

std::copy(std::istream_iterator<binIO<float> >(in),
std::istream_iterator<binIO<float> >(),
std::back_inserter(data));

--
Later,
Jerry.

The universe is a figment of its own imagination.


All times are GMT. The time now is 08:06 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.