递归模板函数迭代几个模板参数

时间:2017-07-13 11:08:59

标签: c++ c++11 templates variadic-templates template-meta-programming

我写了一个可变参数模板,它正在执行一个仿函数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; 
}

3 个答案:

答案 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>());
    }
};

Demo

答案 1 :(得分:1)

给定n个元组,生成它们的交叉乘积(每个元素中包含一个元素的元组,其中包含每个组合)。

给定一个积分常量元组,调用它们的值运行。

给定一个值,生成一个从0到n-1的积分常数元组。

给定一个元组,在每个元素上执行一个函数对象。

3和1定义了要运行的多维数据集。

将该多维数据集与一个执行2的lambda一起传递给4。

虽然写作很有趣,但不值得替换9行代码。上述操作均未在std中预先写好;我假设大多数元编程库都会实现它们。使用std(可能更少)从头开始编写上述每个步骤需要不到50行。

答案 2 :(得分:1)

我提出了一个C ++ 14解决方案(使用std::index_sequencestd::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...) + ... ); }