考虑以下代码:
template < size_t... Indices >
void something(std::index_sequence<Indices...>)
{
// how to obtain the following call where N is sizeof...(Indices)?
// foo(f(0),g(0),f(1),g(1),...,f(N-1),g(N-1));
}
答案 0 :(得分:3)
回答问题的关键:
// how to obtain the following call where N is sizeof...(Indices)?
// foo(f(0),g(0),f(1),g(1),...,f(N-1),g(N-1));
是制定如何实际生成这样的包扩展。我们有2N
个参数,希望:
+=====+======+
| idx | expr |
+-----+------+
| 0 | f(0) |
| 1 | g(0) |
| 2 | f(1) |
| 3 | g(1) |
| ....
+=====+======+
在C ++ 17中,我们可以用if constexpr
:
template <size_t I>
auto expr() {
if constexpr (I % 2 == 0) {
// even indices are fs
return f(I / 2);
} else {
// odds are gs
return g(I / 2);
}
}
甚至可以是以integral_constant
作为参数的lambda。所以我们真的只需要将N
参数转换为2N
个参数,这只是添加更多索引的问题:
template <auto V>
using constant = std::integral_constant<decltype(V), V>;
template < size_t... Indices >
void something(std::index_sequence<Indices...>) {
auto expr = [](auto I) {
if constexpr (I % 2 == 0) {
return f(I / 2);
} else {
return g(I / 2);
}
}
return foo(
expr(constant<Indices>{})..., // 0, ..., N-1
expr(constant<Indices + sizeof...(Indices)>{})... // N, ..., 2N-1
);
}
答案 1 :(得分:2)
我能想象的最好的是使用std::tuple_cat
和std::make_pair
来制作std::tuple
foo()
个参数。
不幸的是,我知道如何只使用辅助函数来调用foo()
template <typename T, std::size_t... I>
void somethingH (T const & t, std::index_sequence<I...> const &)
{ foo(std::get<I>(t)...); }
template <std::size_t... I>
void something (std::index_sequence<I...> const &)
{
somethingH(std::tuple_cat(std::make_pair(f(I), g(I))...),
std::make_index_sequence<(sizeof...(I) << 1)>{});
}
使用仅从C ++ 17开始提供的std::apply
,您可以使用lambda函数选择正确的foo
(如SirGuy建议的那样;谢谢!)并避免使用辅助函数
template <std::size_t... I>
void something (std::index_sequence<I...> const &)
{
std::apply([](auto && ... as)
{ return foo(std::forward<decltype(as)>(as)...); },
std::tuple_cat(std::make_pair(f(I), g(I))...));
}
以下是完整的C ++ 17工作示例
#include <iostream>
#include <utility>
#include <tuple>
int f (std::size_t n)
{ return n; }
int g (std::size_t n)
{ return -n; }
template <typename ... Args>
void foo (Args ... as)
{ (std::cout << ... << as) << std::endl; }
template <std::size_t... I>
void something (std::index_sequence<I...> const &)
{
std::apply([](auto && ... as)
{ return foo(std::forward<decltype(as)>(as)...); },
std::tuple_cat(std::make_pair(f(I), g(I))...));
}
int main()
{
something(std::make_index_sequence<7U>{});
}