【问题标题】:Iterate a template argument list?迭代模板参数列表?
【发布时间】:2012-07-19 13:44:19
【问题描述】:

我正在想办法循环遍历模板参数列表,但没有成功

我不能使用 c++11 可变参数模板功能,它需要在编译时完成

我可以假设在否定论点之后不会有肯定论点

有什么想法吗?

template< int F1, int F2 ,int F3>
struct TemplatedClass
{
    TemplatedClass();
    update()
    {
        /* 
          for each positive template argument 
             call a method
        */
    }
};

【问题讨论】:

  • 模板参数的数量是固定的吗?
  • 它是固定的,(虽然可能很长)

标签: c++ templates metaprogramming c++03


【解决方案1】:

除了编写一系列if 语句之外,您还可以将所有参数放入一个数组并遍历它。这样编译器将无法优化您的代码(您没有指定是否需要这样做),但我认为它看起来会更干净。例如

template<int F1, int F2 ,int F3>
struct TemplatedClass
{ 
    TemplatedClass(); 
    update() 
    {
        const int array[] = {F1, F2, F3};
        // replace this with std::for_each(...) with functors you need
        for (int i = 0; i < sizeof(array)/sizeof(array[0]); ++i)
        {
            myfunc(array[i]);
        }
    } 
} 

【讨论】:

  • 我喜欢这个解决方案,不幸的是 myfunc 在我的情况下也是一个模板,它不会接受 array[i] 因为它不是恒定的。还是谢谢
【解决方案2】:

由于模板参数的数量有限,您可以使用一系列if 语句。

template<int F1, int F2 ,int F3> 
struct TemplatedClass 
{ 
    TemplatedClass(); 
    update() 
    {
    if (F1 > 0) myfunc(); 
    if (F2 > 0) myfunc(); 
    if (F3 > 0) myfunc(); 
        // etc.*  
    } 
} 

【讨论】:

  • 是的,列表可能很长,所以我想尽可能避免它,但它可能是唯一的解决方案
  • @Pierre,我想你已经被它困住了。
  • @Pierre,您可以考虑将int * 传递到静态内存,而不是大量的int
  • 您可以使用 boost 预处理器库,这样您只需编写该行一次,预处理器将根据要求复制它多次。
【解决方案3】:

模板参数的数量固定后,这样的简单代码就可以了:

update()
{
    if (F1 > 0) callAMethod();
    if (F2 > 0) callAMethod();
    if (F3 > 0) callAMethod();
}

if 语句中的表达式是编译时常量,因此优化器会将其优化为等效于调用方法“不受保护”(没有分支)或根本不调用该方法的代码。换句话说,是否调用该方法的决定将由优化器在编译时做出,而不会产生运行时成本。

【讨论】:

    【解决方案4】:

    如果您不确定优化器是否会摆脱ifs,请使用帮助模板:

    void functionToCall(int number) { /* ... */ }
    
    template<bool doCall>
    struct FuncCaller {
        template<typename Callable>
        FuncCaller(Callable func, int number) { func(number); }
    };
    
    template<>
    struct FuncCaller<false> {
        template<typename Callable>
        FuncCaller(Callable, int) {}
    };
    
    update()
    {
        FuncCaller<(F1 > 0)>(functionToCall, F1);
        FuncCaller<(F2 > 0)>(functionToCall, F2);
        FuncCaller<(F3 > 0)>(functionToCall, F3);
    }
    

    【讨论】:

      【解决方案5】:

      您可以尝试使用 Boost 元编程库来执行此操作,但需要您更改类的模板定义以为 Boost MPL 参数腾出空间。

      你想用 Boost::MPL 做的一个例子是:

      #include <boost/mpl/vector.hpp>
      #include <boost/mpl/empty.hpp>
      #include <boost/mpl/back.hpp>
      #include <boost/mpl/pop_back.hpp>
      #include <boost/mpl/if.hpp>
      #include <iostream>
      
      using namespace boost::mpl;
      template<class T>
      class Test {
      public:
        void funcToCall() {
          std::cout << "I'm called\n";
        }
        void update();
      };
      
      template<class Y, class T>
      struct Update {
        static void update(T* t) {
          typedef typename pop_back<Y>::type vec_less;
          if (back<Y>::type::value > 0)
            t->funcToCall();
          Update<typename if_<empty<vec_less>, void, vec_less >::type, T>::update(t);
        }
      };
      template<class T>
      struct Update<void ,T> {
        static void update(T* t) {}
      };
      
      template<class T>
      void Test<T>::update() {
      
      Update<T, Test<T> >::update(this);
      
      }
      
      
      int main() {
        Test<vector<int_<0>,int_<4>, int_<9> > > t;
        t.update();
        return 0;
      }
      

      “Test”类将是您原来的“TemplatedClass”。现在,您无需获取 int 模板参数列表,而是获取一个 boost::mpl::vector 参数。这包含您要传递的所有整数,然后您调用更新函数,该函数将从结构“Update”中递归调用更新方法,如果整数大于 0,则该方法将有责任调用“funcToCall()”方法。

      我上面粘贴的程序的输出是:

      MacBook-Pro-di-Marcello:~ Kariddi$ ./test

      我叫

      我叫

      当然,您需要 Boost 库才能使本示例正常工作。

      您可以在此处找到有关 MPL 的信息:

      http://www.boost.org/libs/mpl/doc/index.html

      干杯, 马塞洛

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-08-29
        • 2021-10-28
        • 2014-08-19
        • 2013-12-10
        • 2019-03-05
        • 1970-01-01
        • 2016-09-20
        相关资源
        最近更新 更多