我写了一个可变参数模板,它正在执行一个仿函数F
完全N
次并累积结果。现在我想知道如何使这个模板能够处理当前名为id
的可变数量的索引(模板)参数以及所需的仿函数x, y, z
。
我想到的是一个类似于下面的仿函数,就好像你把它称为三个for循环一样。我也想知道它是否可以通过参数列表来解决。
struct 3DFunctor {
template <int x, int y, int z>
static int run() {
return x*y*z;
}
};
期望的行为应该是这样的:
accum_for<3,3,3>::get<3DFunctor>();
3DFunctor::run<0,0,0>(/*args ...*/) +
3DFunctor::run<0,0,1>(/*args ...*/) +
3DFunctor::run<0,0,2>(/*args ...*/) +
3DFunctor::run<0,1,0>(/*args ...*/) +
3DFunctor::run<0,1,1>(/*args ...*/) +
3DFunctor::run<0,1,2>(/*args ...*/) +
// ..
示例:
#include <iostream>
#include <string>
struct F {
template <int id>
static int run(int val) {
return id * val;
}
};
template<unsigned int n>
struct accum1d_for {
template <class Funct, class ... ArgTypes>
static auto get(ArgTypes ... args) -> decltype(Funct::template run<0>(args ...)) {
return (
accum1d_for<n-1>::template get<Funct>(args ...) +
Funct::template run<n>(args ...)
);
}
};
template<>
struct accum1d_for<0> {
template <class Funct, class ... ArgTypes>
static auto get(ArgTypes ... args) -> decltype(Funct::template run<0>(args ...)) {
return static_cast<decltype(Funct::template run<0>(args ...))>(0);
}
};
int main()
{
std::cout << accum1d_for<10>::get<F>(2.f) << std::endl;
}
答案 0 :(得分:3)
使用std::index_sequence
,您可以
template <std::size_t N1, std::size_t N2, std::size_t N3>
struct accum_for
{
private:
template <class Funct, std::size_t ... Is>
static int get(std::index_sequence<Is...>) {
int res = 0;
using int_array = int[];
static_cast<void>(int_array{0, (res += Funct::template run<Is / N3 / N2,
(Is / N3) % N2,
Is % N3>())...});
return res;
}
public:
template <class Funct>
static int get() {
return get<Funct>(std::make_index_sequence<N1 * N2 * N3>());
}
};
答案 1 :(得分:1)
给定n个元组,生成它们的交叉乘积(每个元素中包含一个元素的元组,其中包含每个组合)。
给定一个积分常量元组,调用它们的值运行。
给定一个值,生成一个从0到n-1的积分常数元组。
给定一个元组,在每个元素上执行一个函数对象。
3和1定义了要运行的多维数据集。
将该多维数据集与一个执行2的lambda一起传递给4。
虽然写作很有趣,但不值得替换9行代码。上述操作均未在std中预先写好;我假设大多数元编程库都会实现它们。使用std(可能更少)从头开始编写上述每个步骤需要不到50行。
答案 2 :(得分:1)
我提出了一个C ++ 14解决方案(使用std::index_sequence
和std::make_index_sequence()
;如果你需要一个C ++ 11解决方案应该是简单的创建一个替代品。)
我已将constexpr
添加到您的get()
,因此您可以使用它来初始化constexpr
值。
我已经使用std::size_t
代替int
,因为你写了关于&#34; index&#34;,所以它有点简单。
示例
#include <utility>
#include <iostream>
struct Functor3D
{
template <std::size_t x, std::size_t y, std::size_t z>
static constexpr std::size_t run ()
{ return x*y*z; }
};
template <std::size_t ... topIs>
struct accum_for
{
private:
template <std::size_t ... Is>
using IndS = std::index_sequence<Is...>;
template <typename Func, std::size_t ... Is>
static constexpr std::size_t h1 (IndS<Is...> const &)
{ return Func::template run<Is...>(); }
template <typename Func, std::size_t ... I0s,
std::size_t ... Ins, typename ... Ts>
static constexpr std::size_t h1 (IndS<I0s...>, IndS<Ins...>,
Ts const & ... ts)
{
using unused = int[];
std::size_t ret { 0 };
(void)unused { 0,
((void)(ret += h1<Func>(IndS<I0s..., Ins>{}, ts...)), 0)... };
return ret;
}
public:
template <typename Func>
static constexpr std::size_t get ()
{ return h1<Func>(IndS<>{}, std::make_index_sequence<topIs>()...); }
};
int main(void)
{
constexpr std::size_t val { accum_for<3U, 3U, 3U>::get<Functor3D>() };
std::cout << val << std::endl;
}
如果您可以使用C ++ 17,h1()
辅助函数的通用版本(具有unused
数组的函数)可以简化如下
template <typename Func, std::size_t ... I0s,
std::size_t ... Ins, typename ... Ts>
static constexpr std::size_t h1 (IndS<I0s...>, IndS<Ins...>,
Ts const & ... ts)
{ return ( h1<Func>(IndS<I0s..., Ins>{}, ts...) + ... ); }