单行std::getstd::index_sequence?
single-line std::get std::index_sequence?
我有一个 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
进行调用,以便 "unwrap" 调用 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);
}
不幸的是,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);
}
我有一个 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
进行调用,以便 "unwrap" 调用 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);
}
不幸的是,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);
}