C++ 基于运行时决策组合不同的迭代器

C++ 基于运行时决策组合不同的迭代器,c++,boost,visual-studio-2013,iterator,adapter,C++,Boost,Visual Studio 2013,Iterator,Adapter,我有一个算法,给定任意数量的向量,运行一个特定的算法并返回结果 可以从输入文件中读取矢量,输入文件中的行表示csv格式的矢量,或者用户可以指定正整数(大于2)n、k、m,程序将生成n个矢量,其中k个坐标中的每一个都随机分布在[0、m-1]范围内 用户可以在几个可应用于每个向量的函数之间进行选择,例如,将每个函数乘以一个标量,将模应用于每个元素,将第N个坐标置零等 我所考虑的解决方案是使用迭代器,就像使用标准算法一样(例如 模板 int my_转换(输入开始,输入结束){ //从头到尾 返回结果;

我有一个算法,给定任意数量的向量,运行一个特定的算法并返回结果

可以从输入文件中读取矢量,输入文件中的行表示csv格式的矢量,或者用户可以指定正整数(大于2)n、k、m,程序将生成n个矢量,其中k个坐标中的每一个都随机分布在[0、m-1]范围内

用户可以在几个可应用于每个向量的函数之间进行选择,例如,将每个函数乘以一个标量,将模应用于每个元素,将第N个坐标置零等

我所考虑的解决方案是使用迭代器,就像使用标准算法一样(例如

模板
int my_转换(输入开始,输入结束){
//从头到尾
返回结果;
}
当我使用它作为参数时,它是有效的,我很有信心我会使用它来生成值并应用所需的函数,但我不太确定如何根据用户输入在运行时进行这些组合

我可以在执行
my_transform
之前聚合所有用户输入,但是我如何将其应用于结果迭代器,因为它可以是
std::istream_迭代器
boost::transform_迭代器
boost::function_input_迭代器

附言:

  • 正如我在VS13上工作的标签中提到的,所以解决方案应该与它兼容
  • 迭代不止一次不是一个选项,因为这些文件可能会变得相当大

我想您需要的是增压范围

  • 加入
  • 任何范围
    (基于
    任何变形器
或者,您可以重新设计算法,使其在默认情况下以“流”模式工作,并动态写入输出迭代器

更新演示程序 下面的示例演示了如何连接输入范围(不同类型)的任意组合,然后在其组合元素上应用任意转换函数序列

主程序如下所示:

int main(int argc, char const** argv) {
    using InIt = std::istream_iterator<int>;

    if (argc!=4) return 255;
    std::ifstream f1(argv[1]), f2(argv[2]), f3(argv[3]);

    auto r1 = boost::make_iterator_range(InIt(f1), {}),
         r2 = boost::make_iterator_range(InIt(f2), {}),
         r3 = boost::make_iterator_range(InIt(f3), {});    
    auto r4 = boost::make_iterator_range(boost::make_function_input_iterator(r10gen_, 0), { r10gen_, 10 });

    srand(time(0));
    for (int i : random_compose_input(r1,r2,r3,r4) 
               | transformed(random_transform(
                    [](int i) { return i/3; },
                    [](int i) { return -4*i; },
                    [](int i) { return 100+i; },
                    [](int i) { return sqrt(abs(i)); }
                 ))
        )
    { 
        std::cout << i << " ";
    }
}
注意
multi_join
join
的用武之地。请参阅完整的程序清单,了解使用可变函数模板实现此功能的(直接)方法

随机_变换
组合发生在
boost::function

(请注意,行为与静态已知lambda的组成存在细微差异:lambda具有推断的返回类型(例如,对于执行
sqrt(abs(i))的lambda而言,
double
),并保留该类型。由于
boost::function
会删除此信息,因此它会隐式强制转换序列中的每一步执行
int
。)

警告:2个库错误 这里有两个库错误:

  • 哪个有分辨率

  • 另一个我不知道的bug,
    任何迭代器
    在不添加构造函数重载的情况下无法包装
    函数(输入)迭代器

    function_input_iterator(base_type const& b) : base_type(b) {};
    
    这是因为在某一点上,
    任何迭代器
    都只会继续使用基类(这可能在
    函数输入迭代器
    库中修复)

  • 完整代码 由于上面提到的bug,它并没有在Coliru上运行,但这里有一个完整的程序,可以在我的GCC和clang安装上以c++11模式编译:

    #include <boost/function.hpp>
    #include <boost/range.hpp>
    #include <boost/range/adaptors.hpp>
    #include <boost/range/any_range.hpp>
    #include <boost/range/join.hpp>
    #include <boost/iterator/function_input_iterator.hpp>
    
    using namespace boost::adaptors;
    
    #include <iostream>
    #include <fstream>
    #include <vector>
    
    /////////////////////////////////////////////
    // multi_join utility
    namespace detail {
        struct multi_join_dispatch {
            template <typename R1> static R1 call(R1&& r1) 
                { return std::forward<R1>(r1); }
    
            template <typename R1, typename... Rs> static auto call(R1&& r1, Rs&&... ranges) 
                -> decltype(boost::range::join(std::forward<R1>(r1), call(std::forward<Rs>(ranges)...)))
                { return boost::range::join(std::forward<R1>(r1), call(std::forward<Rs>(ranges)...)); }
        };
    }
    
    template <typename... Rs> auto multi_join(Rs&&... ranges) 
        -> decltype(detail::multi_join_dispatch::call(std::forward<Rs>(ranges)...))
        { return detail::multi_join_dispatch::call(std::forward<Rs>(ranges)...); }
    
    /////////////////////////////////////////////
    // generate random numbers [0..9]
    struct r10gen {
        typedef int result_type;
        int operator()() const { return rand()%10; } 
    } static r10gen_;
    
    /////////////////////////////////////////////
    // runtime composition of any input ranges
    using AnyR = boost::any_range<int const, boost::single_pass_traversal_tag, int>;
    
    template <typename R1, typename R2, typename R3, typename R4>
        AnyR random_compose_input(R1 const& r1, R2 const& r2, R3 const& r3, R4 const& r4) 
    {
        int select = rand()%16;
        std::cout << "selected inputs " << std::showbase << std::hex << select << std::dec << "\n";
        switch(select) {
            case  0:
                static int const* dummy = nullptr;
                return boost::make_iterator_range(dummy, dummy);
            case  1: return multi_join(r1            );
            case  2: return multi_join(    r2        );
            case  3: return multi_join(r1, r2        );
            case  4: return multi_join(        r3    );
            case  5: return multi_join(r1,     r3    );
            case  6: return multi_join(    r2, r3    );
            case  7: return multi_join(r1, r2, r3    );
            case  8: return multi_join(            r4);
            case  9: return multi_join(r1,         r4);
            case 10: return multi_join(    r2,     r4);
            case 11: return multi_join(r1, r2,     r4);
            case 12: return multi_join(        r3, r4);
            case 13: return multi_join(r1,     r3, r4);
            case 14: return multi_join(    r2, r3, r4);
            case 15: return multi_join(r1, r2, r3, r4);
        }
        throw "oops";
    }
    
    /////////////////////////////////////////////
    // random composition of transformation
    using Xfrm = boost::function<int(int)>;
    
    template <typename F1, typename F2, typename F3, typename F4>
        Xfrm random_transform(F1 const& f1, F2 const& f2, F3 const& f3, F4 const& f4) 
    {
        int select = rand()%16;
        std::cout << "selected transforms " << std::showbase << std::hex << select << std::dec << "\n";
        switch(select) {
            case  0: return [=](int i){ return   (  (  (  (i)))); };
            case  1: return [=](int i){ return   (  (  (f1(i)))); };
            case  2: return [=](int i){ return   (  (f2(  (i)))); };
            case  3: return [=](int i){ return   (  (f2(f1(i)))); };
            case  4: return [=](int i){ return   (f3(  (  (i)))); };
            case  5: return [=](int i){ return   (f3(  (f1(i)))); };
            case  6: return [=](int i){ return   (f3(f2(  (i)))); };
            case  7: return [=](int i){ return   (f3(f2(f1(i)))); };
            case  8: return [=](int i){ return f4(  (  (  (i)))); };
            case  9: return [=](int i){ return f4(  (  (f1(i)))); };
            case 10: return [=](int i){ return f4(  (f2(  (i)))); };
            case 11: return [=](int i){ return f4(  (f2(f1(i)))); };
            case 12: return [=](int i){ return f4(f3(  (  (i)))); };
            case 13: return [=](int i){ return f4(f3(  (f1(i)))); };
            case 14: return [=](int i){ return f4(f3(f2(  (i)))); };
            case 15: return [=](int i){ return f4(f3(f2(f1(i)))); };
        }
        throw "oops";
    }
    
    int main(int argc, char const** argv) {
        using InIt = std::istream_iterator<int>;
    
        if (argc!=4) return 255;
        std::ifstream f1(argv[1]), f2(argv[2]), f3(argv[3]);
    
        auto r1 = boost::make_iterator_range(InIt(f1), {}),
             r2 = boost::make_iterator_range(InIt(f2), {}),
             r3 = boost::make_iterator_range(InIt(f3), {});
    
        auto fi_b = boost::make_function_input_iterator(r10gen_, 0);
        auto fi_l = boost::make_function_input_iterator(r10gen_, 10);
        auto r4 = boost::make_iterator_range(fi_b, fi_l);
    
        srand(time(0));
        for (int i : random_compose_input(r1,r2,r3,r4) 
                   | transformed(random_transform(
                        [](int i) { return i/3; },
                        [](int i) { return -4*i; },
                        [](int i) { return 100+i; },
                        [](int i) { return sqrt(abs(i)); }
                     ))
            )
        { 
            std::cout << i << " ";
        }
    }
    
    或者,例如

    selected transforms 0x1
    selected inputs 0x8
    0 0 2 2 0 1 2 1 1 2 
    

    谢谢你的回答!但是join对我有什么好处呢?因为它连接了两个流,并且没有实现我所寻找的函数组合的等效性(例如,对于每个向量v,在将n坐标归零后,通过标量将v多重化,其中每个v都是文件中的一行)。也许我在文档中遗漏了一些东西,所以请举一个小例子。我是否可以只使用
    any\u range
    的页面中提到的
    any\u迭代器
    ?我不知道您/也/想要编写转换函数。但是,是的,它对两个作业的工作方式都与
    any\u*
    时代相同使用
    std::function
    (或
    boost::function
    )仅使用
    join
    连接范围并单独组合转换函数似乎要容易得多(因此您可以得到一个复合函子,而不是更多的迭代器层)我添加了一个™ 演示我的意思。希望这能有所帮助:)哇,这当然是荒谬的全面。这确实很有帮助。我很佩服你的耐心(TBH:)@我认为,大流士的坚韧是造就程序员的重要因素。干杯
     boost::function<int(int)> xfrm = [](int i){return i;};
    
     while (std::getline(std::cin, line))
     {
         if      (line == "+2") xfrm = [=](int i) { return xfrm(i) + 2 };
         else if (line == "-2") xfrm = [=](int i) { return xfrm(i) - 2 };
         else if (line == "*2") xfrm = [=](int i) { return xfrm(i) * 2 };
         else if (line == "/2") xfrm = [=](int i) { return xfrm(i) / 2 };
     }
    
    function_input_iterator(base_type const& b) : base_type(b) {};
    
    #include <boost/function.hpp>
    #include <boost/range.hpp>
    #include <boost/range/adaptors.hpp>
    #include <boost/range/any_range.hpp>
    #include <boost/range/join.hpp>
    #include <boost/iterator/function_input_iterator.hpp>
    
    using namespace boost::adaptors;
    
    #include <iostream>
    #include <fstream>
    #include <vector>
    
    /////////////////////////////////////////////
    // multi_join utility
    namespace detail {
        struct multi_join_dispatch {
            template <typename R1> static R1 call(R1&& r1) 
                { return std::forward<R1>(r1); }
    
            template <typename R1, typename... Rs> static auto call(R1&& r1, Rs&&... ranges) 
                -> decltype(boost::range::join(std::forward<R1>(r1), call(std::forward<Rs>(ranges)...)))
                { return boost::range::join(std::forward<R1>(r1), call(std::forward<Rs>(ranges)...)); }
        };
    }
    
    template <typename... Rs> auto multi_join(Rs&&... ranges) 
        -> decltype(detail::multi_join_dispatch::call(std::forward<Rs>(ranges)...))
        { return detail::multi_join_dispatch::call(std::forward<Rs>(ranges)...); }
    
    /////////////////////////////////////////////
    // generate random numbers [0..9]
    struct r10gen {
        typedef int result_type;
        int operator()() const { return rand()%10; } 
    } static r10gen_;
    
    /////////////////////////////////////////////
    // runtime composition of any input ranges
    using AnyR = boost::any_range<int const, boost::single_pass_traversal_tag, int>;
    
    template <typename R1, typename R2, typename R3, typename R4>
        AnyR random_compose_input(R1 const& r1, R2 const& r2, R3 const& r3, R4 const& r4) 
    {
        int select = rand()%16;
        std::cout << "selected inputs " << std::showbase << std::hex << select << std::dec << "\n";
        switch(select) {
            case  0:
                static int const* dummy = nullptr;
                return boost::make_iterator_range(dummy, dummy);
            case  1: return multi_join(r1            );
            case  2: return multi_join(    r2        );
            case  3: return multi_join(r1, r2        );
            case  4: return multi_join(        r3    );
            case  5: return multi_join(r1,     r3    );
            case  6: return multi_join(    r2, r3    );
            case  7: return multi_join(r1, r2, r3    );
            case  8: return multi_join(            r4);
            case  9: return multi_join(r1,         r4);
            case 10: return multi_join(    r2,     r4);
            case 11: return multi_join(r1, r2,     r4);
            case 12: return multi_join(        r3, r4);
            case 13: return multi_join(r1,     r3, r4);
            case 14: return multi_join(    r2, r3, r4);
            case 15: return multi_join(r1, r2, r3, r4);
        }
        throw "oops";
    }
    
    /////////////////////////////////////////////
    // random composition of transformation
    using Xfrm = boost::function<int(int)>;
    
    template <typename F1, typename F2, typename F3, typename F4>
        Xfrm random_transform(F1 const& f1, F2 const& f2, F3 const& f3, F4 const& f4) 
    {
        int select = rand()%16;
        std::cout << "selected transforms " << std::showbase << std::hex << select << std::dec << "\n";
        switch(select) {
            case  0: return [=](int i){ return   (  (  (  (i)))); };
            case  1: return [=](int i){ return   (  (  (f1(i)))); };
            case  2: return [=](int i){ return   (  (f2(  (i)))); };
            case  3: return [=](int i){ return   (  (f2(f1(i)))); };
            case  4: return [=](int i){ return   (f3(  (  (i)))); };
            case  5: return [=](int i){ return   (f3(  (f1(i)))); };
            case  6: return [=](int i){ return   (f3(f2(  (i)))); };
            case  7: return [=](int i){ return   (f3(f2(f1(i)))); };
            case  8: return [=](int i){ return f4(  (  (  (i)))); };
            case  9: return [=](int i){ return f4(  (  (f1(i)))); };
            case 10: return [=](int i){ return f4(  (f2(  (i)))); };
            case 11: return [=](int i){ return f4(  (f2(f1(i)))); };
            case 12: return [=](int i){ return f4(f3(  (  (i)))); };
            case 13: return [=](int i){ return f4(f3(  (f1(i)))); };
            case 14: return [=](int i){ return f4(f3(f2(  (i)))); };
            case 15: return [=](int i){ return f4(f3(f2(f1(i)))); };
        }
        throw "oops";
    }
    
    int main(int argc, char const** argv) {
        using InIt = std::istream_iterator<int>;
    
        if (argc!=4) return 255;
        std::ifstream f1(argv[1]), f2(argv[2]), f3(argv[3]);
    
        auto r1 = boost::make_iterator_range(InIt(f1), {}),
             r2 = boost::make_iterator_range(InIt(f2), {}),
             r3 = boost::make_iterator_range(InIt(f3), {});
    
        auto fi_b = boost::make_function_input_iterator(r10gen_, 0);
        auto fi_l = boost::make_function_input_iterator(r10gen_, 10);
        auto r4 = boost::make_iterator_range(fi_b, fi_l);
    
        srand(time(0));
        for (int i : random_compose_input(r1,r2,r3,r4) 
                   | transformed(random_transform(
                        [](int i) { return i/3; },
                        [](int i) { return -4*i; },
                        [](int i) { return 100+i; },
                        [](int i) { return sqrt(abs(i)); }
                     ))
            )
        { 
            std::cout << i << " ";
        }
    }
    
    watch ./test <(echo {100..110}) <(echo {200..220}) <(echo {300..330})
    
    selected transforms 0x3
    selected inputs 0x2
    -264 -268 -268 -268 -272 -272 -272 -276 -276 -276 -280 -280 -280 -284 -284 -284 -288 -288 -288 -292 -292
    
    selected transforms 0x1
    selected inputs 0x8
    0 0 2 2 0 1 2 1 1 2