代码之家  ›  专栏  ›  技术社区  ›  Steve Lorimer

单行std::get std::index\u序列?

  •  0
  • Steve Lorimer  · 技术社区  · 7 年前

    我有一个 std::tuple ,我想用 std::index_sequence 为了调用可变函数模板

    考虑下面的示例代码:

    #include <iostream>
    #include <tuple>
    
    template<typename... Ts>
    void foo(const std::string& s, Ts... ts)
    {
        std::cout << "foo called with " << s << " and " << sizeof...(Ts) << " ts\n";
    }
    
    template<typename Tuple, std::size_t... Ixs>
    void call_foo(const std::string& s, Tuple& t, std::index_sequence<Ixs...>)
    {
        foo(s, std::get<Ixs>(t)...);
    }
    
    template<typename... Ts>
    struct Bar
    {
        Bar(Ts... ts) : t(ts...)
        { }
    
        void do_it()
        {
            call_foo("hi", t, std::make_index_sequence<std::tuple_size<decltype(t)>::value>{});
        }
    
        std::tuple<Ts...> t;
    };
    
    template<typename... Ts> Bar<Ts...> make_bar(Ts... ts) { return Bar<Ts...>(ts...); }
    
    int main ()
    {
        auto bar = make_bar(1, 'a', 2.3);
        bar.do_it();
    }
    

    注意,我必须打过去 call_foo index_sequence 为了 “展开” 这个 索引序列 打电话 std::get...

    打电话给吴福 函数,并调用 foo

    也就是说,直接在调用站点打开元组?

    1 回复  |  直到 7 年前
        1
  •  2
  •   HolyBlackCat    7 年前

    如果你不想或不能使用 std::apply ,我可以提出一些备选方案。

    下面的代码片段基于您问题的上一个修订版,该修订版没有 class Bar

    (1) 你可以代替 call_foo

    #include <cstddef>
    #include <iostream>
    #include <tuple>
    #include <utility>
    
    template<typename... Ts>
    void foo(const std::string& s, Ts... ts)
    {
        std::cout << "foo called with " << s << " and " << sizeof...(Ts) << " ts\n";
    }
    
    template<typename... Ts>
    void bar(Ts... ts)
    {
        const std::string s = "hello world";
        const auto t = std::make_tuple(ts...);
    
        [&]<std::size_t ...I>(std::index_sequence<I...>)
        {
            foo(s, std::get<I>(t)...);
        }
        (std::make_index_sequence<std::tuple_size_v<decltype(t)>>{});
    }
    
    int main()
    {
        bar(1, 'a', 2.3);
    }
    

    Try it live

    不幸的是,GCC8目前似乎是唯一支持这些功能的主要编译器。


    如果您的编译器没有新的高级lambda,或者您不想编写 index_sequence 样板每次需要展开元组时,我建议如下:

    #include <cstddef>
    #include <iostream>
    #include <tuple>
    #include <utility>
    
    template <std::size_t ...I, typename F> void with_sequence_impl(F &&func, std::index_sequence<I...>)
    {
        func(std::integral_constant<std::size_t, I>{}...);
    }
    
    template <std::size_t N, typename F> void with_sequence(F &&func)
    {
        with_sequence_impl(std::forward<F>(func), std::make_index_sequence<N>{});
    }
    
    template<typename... Ts>
    void foo(const std::string& s, Ts... ts)
    {
        std::cout << "foo called with " << s << " and " << sizeof...(Ts) << " ts\n";
    }
    
    template<typename... Ts>
    void bar(Ts... ts)
    {
        const std::string s = "hello world";
        const auto t = std::make_tuple(ts...);
    
        with_sequence<std::tuple_size_v<decltype(t)>>([&](auto ... i)
        {
            foo(s, std::get<i.value>(t)...);
        });
    }
    
    int main()
    {
        bar(1, 'a', 2.3);
    }
    

    Try it live