1

I have a legacy code in which the interface is defined for pointer only and I am trying to adapt some functions to take iterators.

In the answers to this question Address of a dereferenced InputIterator? The case of istream_iterator it was noted that std::istream_iterators are InputIterator. However they are special among InputIterators, because their dereference is guarantied to generate a language reference T const&.

The code for a general input iterator would look like this, notice that I have to generate a copy of the value type to take the address.

#include<iostream>
#include<iterator>
#include<sstream>

void f_legacy(double const* t){
    std::cout << *t << std::endl;
};

template<class InputIt>
void f_aux(InputIt it, std::input_iterator_tag){
    using value_type = typename std::iterator_traits<InputIt>::value_type;
    value_type v = *it; // creates a local copy, *might be* unnecessary
    f_legacy(std::addressof(v));
}

template<class It>
void f(It it){
    f_aux(it, typename std::iterator_traits<It>::iterator_category{});
}
int main(){
    double d = 5.;
    std::istringstream iss("1 2 3");
    std::istream_iterator<double> it(iss);
    f_legacy(&d);
    f(it);
}

However for std::istream_iterator this is not optimal because an unnecessary copy is made. (I don't know if it can be optimized, but that is another question.) So I could add an overload to handle the optimizations for istream_iterator.

void f(std::istream_iterator<double> it){
    f_legacy(std::addressof(*it));
}

or more verbose

void f(std::istream_iterator<double> it){
    double const& v = *it; // no copy is made
    f_legacy(std::addressof(v));
}

The question is, can I just use this following version of f without writing an overload of istream_iterator?

template<class InputIt>
void f_aux(InputIt it, std::input_iterator_tag){
    using value_type = typename std::iterator_traits<InputIt>::value_type;
    value_type const& v = *it; // a "copy" is made only if necessary
    f_legacy(std::addressof(v));
}

I think this should work due to https://herbsutter.com/2008/01/01/gotw-88-a-candidate-for-the-most-important-const/ , but I am not sure if it applies.

or even this one liner:

template<class InputIt>
void f_aux(InputIt it, std::input_iterator_tag){
    using value_type = typename std::iterator_traits<InputIt>::value_type;
    f_legacy(std::addressof(static_cast<value_type const&>(*it)));
}

Note: In the real code all the functions are templated, double is just a placeholder here.

3
  • 1
    The one liner should work: static.cast. If *it is a pr-value a temporary is materialized to hold the value, this temporary will last until the end of the full expression. if *it is an l-value the result of the static_cast will be a reference directly bound to *it. Commented Mar 14, 2018 at 20:53
  • @Oliv, thanks, I think it would work only because of the const& in the static cast. Commented Mar 14, 2018 at 20:55
  • 1
    Indeed a & without the const would not have work: dlc.init.ref Commented Mar 14, 2018 at 21:01

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.