Optimize InputIterator dereference without making

2019-07-31 04:30发布

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.

0条回答
登录 后发表回答