提升function_input_iterator范围的快捷语法

Shortcut syntax for boost function_input_iterator range

本文关键字:语法 iterator function input 提升 范围      更新时间:2023-10-16

我想知道这种代码是否有快捷方式语法:

#include <boost/iterator/function_input_iterator.hpp>
#include <boost/range.hpp>
int main() {
    std::function<int (int)> f = [](int i) -> int {
       // some logic, return int
    };
    auto r = boost::make_iterator_range(boost::make_function_input_iterator(f, 0), boost::make_function_input_iterator(f, 10));
    return 0;
}

两个注意事项:

  • 我无法使用auto f = [](int i) ->int {...};,因为这会导致:

error: no type named 'result_type' in 'struct main()::<lambda(int)>'

出于某种原因,使用 std::function 可以修复它。

  • 此外,我不能将f作为临时内联传递,即boost::make_function_input_iterator([](int i) ->int {...}, ...因为该函数通过引用获取 f。

理想情况下,我希望能够做到:

make_function_input_range(0, 10, [](int i)->int {...});

您可以使用添加 typedef 的简单包装器:

template <typename F>
struct ref_wrap : std::reference_wrapper<F> {
    typedef decltype(std::declval<F>()() result_type;
    ref_wrap(F& f) : std::reference_wrapper<F>(f) {}
};

我使用引用包装器来满足function_input_iterator的要求,这已经要求该函数是左值引用。实际上,您现在可以将其抛在脑后,因为我们返回了函数包装器和范围,请参见下文

接下来,有一个帮助程序,它返回该包装器的元组以及基于它构建的迭代器范围:

template <typename F>
struct input_function_range_wrapper {
    struct ref_wrap : std::reference_wrapper<F> {
        typedef decltype(std::declval<F>()()) result_type;
        ref_wrap(F& f) : std::reference_wrapper<F>(f) {}
    } wrap;
    using It = boost::function_input_iterator<ref_wrap, int>;
    boost::iterator_range<It> range;
    template <typename V>
    input_function_range_wrapper(F& f, V a, V b) : wrap(f), range(It(wrap, a), It(wrap, b))
    { }
};

为了方便使用它,让我们将其移动到 detail 命名空间中并添加一个工厂函数:

template <typename F, typename V = int>
auto make_input_function_range(F& f, V a, V b) {
    return detail::input_function_range_wrapper<F>(f, a, b);
}

现在最重要的是,我们添加了启用 ADL 的beginend调用和 PRONTO,我们可以在其上使用 c++ 的 ranged-for:

int main() {
    auto f = [i=1]() mutable { return i*=2; };
    for (auto v : make_input_function_range(f, 0, 10)) {
        std::cout << v << " ";
    }
}

指纹

2 4 8 16 32 64 128 256 512 1024 

完整演示

住在科里鲁

#include <boost/iterator/function_input_iterator.hpp>
#include <boost/range.hpp>
namespace detail {
    template <typename F>
    struct input_function_range_wrapper {
        struct ref_wrap : std::reference_wrapper<F> {
            typedef decltype(std::declval<F>()(/*std::declval<V>()*/)) result_type;
            ref_wrap(F& f) : std::reference_wrapper<F>(f) {}
        } wrap;
        using It = boost::function_input_iterator<ref_wrap, int>;
        boost::iterator_range<It> range;
        template <typename V>
        input_function_range_wrapper(F& f, V a, V b) : wrap(f), range(It(wrap, a), It(wrap, b))
        { }
    };
    template <typename... Ts>
        auto begin(input_function_range_wrapper<Ts...>& r)       { return r.range.begin(); }
    template <typename ... Ts>
        auto begin(input_function_range_wrapper<Ts...> const& r) { return r.range.begin(); }
    template <typename ... Ts>
        auto end  (input_function_range_wrapper<Ts...>& r)       { return r.range.end  (); }
    template <typename ... Ts>
        auto end  (input_function_range_wrapper<Ts...> const& r) { return r.range.end  (); }
}
template <typename F, typename V = int>
auto make_input_function_range(F& f, V a, V b) {
    return detail::input_function_range_wrapper<F>(f, a, b);
}
#include <iostream>
int main() {
    auto f = [i=1]() mutable { return i*=2; };
    for (auto v : make_input_function_range(f, 0, 10)) {
        std::cout << v << " ";
    }
}

有关error: no type named 'result_type',请参阅此错误。

make_function_input_range编写起来很简单,但由于上述错误,这不能与普通 lambda 一起使用:

template<class T>
auto make_function_input_range(std::size_t begin, std::size_t end, T& f) {
    return boost::make_iterator_range(
        boost::make_function_input_iterator(f, begin),
        boost::make_function_input_iterator(f, end));
}

为了解决这个错误,我会创建一个定义所需result_type的小帮助程序类型,而不是使用类型擦除std::function

template<class T>
struct fun_wrapper {
    T f;
    using result_type = typename boost::function_types::result_type<T>;
    template<class... Args>
    result_type operator() (Args&&... args) const {
        return f(std::forward<Args>(args)...);
    }
};
template<class T>
auto make_fun_wrapper(T&& f) {
    return fun_wrapper<T>{std::forward<T>(f)};
}
int main() {
    auto wrapped_f = make_fun_wrapper([](int i)->int {/*...*/});
    auto range = make_function_input_range(0, 10, wrapped_f);
}