tags:

views:

79

answers:

4

Hi everybody!

It's time for another 'how do i do this in c++ without loosing my grip'-question!

This time:

Considering the following code taken from cplusplus.com:

template<class InputIterator, class OutputIterator>
  OutputIterator copy ( InputIterator first, InputIterator last, OutputIterator result )
{
  while (first!=last) *result++ = *first++;
  return result;
}

Is there a way to cast *first to the type of *result?

In other words: is there a way to determine (at compiletime) the type of result?

+6  A: 

yes, the type of *result is ('cause the type of result is OutputIterator )

typename std::iterator_traits<OutputIterator>::value_type

of course, if OutputIterator is a pointer or a correctly written STL-compatible iterator. Otherwise, no, I think there is no way. In the upcoming C++0x, it would be much easier, that is,

decltype(*result)

HTH,

Armen

Armen Tsirunyan
This only answers half the question (how to get the value type of the output iterator, but not how to make `copy` perform the cast on every element
jalf
great!that actually saved my day :)
Florian
jalf: I think the first half of the question was a misphrasing of the second part
Armen Tsirunyan
@jalf:yes ... but that part is 90% ... performing the cast is as easy as: typedef std::iterator_traits<T>::value_type TType; T foo = TType(anyOtherType);
Florian
@Florian: don't forget the 'typename', it is essential, i.e. typedef typename std::iterator_traits..... :)
Armen Tsirunyan
hmm... it compiles fine without the typename in VS2005... but i added it just to be sure.
Florian
@Florian: well, that's because microsoft doesn't do two-phase lookup. But the standard requires that in this situation typename be explicitly used
Armen Tsirunyan
ah thanks for enlightening me here ... i'm from a java and linux background ... so most of this is completly unknown to me
Florian
+1  A: 

Not a precise answer to your question, but it sounds like you want don't really want to std::copy, you want to std::transform your data to another type. In which case, do something like:

template <typename A, typename B>
B convert(A x) { return static_cast<B>(x); }

...

std::transform(v1.begin(), v1.end(), v2.begin(), convert<float,int>);
Oli Charlesworth
and where exactly did you deduce int and float from? The question was, as I understood it, how to retrieve the value type of an iterator in generic code.
Armen Tsirunyan
@Armen: It's an example! Obviously this can be parameterised more generically. The point of my answer is that you don't need to reinvent the STL...
Oli Charlesworth
A: 

You can modify the copy routine to use a template to do the casting...

template <typename A, typename B>                                               
const A& cast(const A&, const B& b)                                             
{                                                                               
    return *reinterpret_cast<const A*>(&b);                                     
};                                                                              

template <class InputIterator, class OutputIterator>                            
OutputIterator mycopy(InputIterator first, InputIterator last,                    
                      OutputIterator result)                                      
{                                                                               
    for ( ; first != last; ++first, ++result)                                   
        *result = cast(*result, *first);                                        
    return result;                                                              
}

That said, Oli's answer's much better if your not specifically looking to learn how to modify copy to handle this....

Tony
+1  A: 

The short answer is no. If OutputIterator is really an OutputIterator (e.g. an ostream_iterator), then: typename std::iterator_traits::value_type will be void, and in C++0x, decltype(*result) is likely to be OutputIterator. (So Armen's suggestion doesn't work in template code.)

And Tony's suggestion involving reinterpret_cast doesn't work either. In fact, it will break things that do work (e.g. when InputIterator is returning int, and OutputIterator wants double).

The only real answer is Oli's. Which is logical: what you really want to do is transform your data, not just copy it.

James Kanze
@James: 1."and in C++0x, decltype(*result) is likely to be OutputIterator" Why? "2.If OutputIterator is really an OutputIterator (e.g. an ostream_iterator), then...". Well, technically speaking you are right, but one can specialize the iterator_traits for output_iterator, can't he?
Armen Tsirunyan
Although Oli's answer doesn't cover how he's going to deduce what type to convert to either. As to specializing `iterator_traits`, isn't it technically illegal (only specializations in std namespace allowed for *user-defined* types)? - But you could create your own iterator traits, and specialize *that* for `ostream_iterator`.
UncleBens
You aren't allowed to specialize anything in std::, except ifthe specialization involves one of your classes. How do youknow that the implementation hasn't already specializediterator_traits for ostream_iterator, for some particularreasons of its own?
James Kanze