c++ - 单行 std::get std::index_sequence?

标签 c++ stdtuple

我有一个 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 才能“展开” index_sequence用于调用 std::get...

是否可以放弃中间的call_foo函数,直接调用foo

也就是说,直接在调用点解包元组?

最佳答案

如果您不想或不能使用 std::apply,我可以建议一些替代方案。

下面的片段是基于你的问题的先前修订,其中没有 class Bar。相同的解决方案也适用于新修订版。

(1) 您可以将 call_foo 替换为带有显式模板参数列表的 C++20 lambda:

#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

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


(2) 如果您的编译器没有新奇的 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

关于c++ - 单行 std::get std::index_sequence?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54013777/

相关文章:

c++ - 为什么为 T 推导的类型是 const int in void func(T const &t)

c++ - 按照运行时定义的顺序遍历 C++ 元组

c++ - 使用C++ 11基于范围的正确方法是什么?

c++ - tuple_map 应该返回什么?

c++ - 为什么 std::get 没有接受转发引用的单一签名

C++ 从 std::vector<std::tuple<int, float>> 获取 std::vector<int>

c++ - Qt : multiple defined symbols found

c++ - 无法使用 std::for_each() 和 std::bind() 过滤 vector 中的元素并将这些过滤后的元素放入新 vector 中

c++ - "error: no viable conversion from tuple..."使用 make_tuple

c++ - 将元组参数转发给 VS2012 中的函数