迭代一个模板参数列表?

3
我正在尝试找到一种循环遍历模板参数列表的方法,但没有成功。
我不能使用C++11可变模板特性,并且需要在编译时完成。
我可以假设在负数参数之后不会有正数参数。
有任何想法吗?
template< int F1, int F2 ,int F3>
struct TemplatedClass
{
    TemplatedClass();
    update()
    {
        /* 
          for each positive template argument 
             call a method
        */
    }
};

模板参数的数量是固定的吗? - Armen Tsirunyan
是的,它是固定的(尽管可能会很长)。 - Pierre Lacave
5个回答

5

你可以将所有的参数放到一个数组中,然后遍历它,而不是写一系列的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],因为它不是常量。无论如何,谢谢。 - Pierre Lacave

3
由于您将拥有有限数量的模板参数,因此可以使用一系列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 Lacave
@Pierre,我认为你被卡住了。 - ThomasMcLeod
1
@Pierre,你可以考虑传递指向静态内存的 int *,而不是大量的 int - ThomasMcLeod
你可以使用boost预处理器库,这样你只需要编写一行代码,预处理器就会根据需要将其复制多次。 - Marc Glisse

2

如果模板参数的数量是固定的,像这样简单的代码就可以:

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

if语句中的表达式是编译时常量,因此优化器将其优化为等效于调用方法"unguarded"(无分支)或根本不调用该方法的代码。换句话说,编译器会在编译时通过优化器决定是否调用该方法,而不会产生运行时成本。


1

如果您不确定优化器是否会去掉 if,可以使用辅助模板:

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);
}

0

你可以尝试使用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参数。其中包含您要传递的所有int,然后调用update函数,该函数将递归调用来自结构“Update”的update方法,该方法将负责在int大于0时调用“funcToCall()”方法。
上面粘贴的程序的输出为:
MacBook-Pro-di-Marcello:〜 Kariddi $ ./test 我被叫了 我被叫了
当然,您需要Boost libs才能使此示例正常工作。
您可以在此处找到有关MPL的信息:

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

祝好, 马塞洛


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接