创建跳转表数组,然后调用。目标是创建一个包含各种函数的数组,然后进行数组查找并调用所需函数。
首先,我会用C++11来做。C++1y 包含自己的整数序列类型,并且有易于编写的auto返回类型:C++11版本将返回void。
我们的函数类大致如下:
struct example_functor {
template<unsigned N>
static void action(double d) const {
std::cout << N << ":" << d << "\n";
}
};
在C++11中,我们需要一些样板代码:
template<unsigned...> struct indexes {};
template<unsigned Max, unsigned... Is> struct make_indexes:make_indexes< Max-1, Max-1, Is... > {};
template<unsigned... Is> struct make_indexes<0, Is...>:indexes<Is...> {};
创建并匹配索引包的模式。
接口如下所示:
template<typename Functor, unsigned Max, typename... Ts>
void invoke_jump( unsigned index, Ts&&... ts )
并且被称为:
invoke_jump<example_functor, 10>( 7, 3.14 );
我们首先创建一个助手:
template<typename Functor, unsigned... Is, typename... Ts>
void do_invoke_jump( unsigned index, indexes<Is...>, Ts&&... ts ) {
static auto table[]={ &(Functor::template action<Is>)... };
table[index]( std::forward<Ts>(ts)... )
}
template<typename Functor, unsigned Max, typename... Ts>
void invoke_jump( unsigned index, Ts&&... ts ) {
do_invoke_jump( index, make_indexes<Max>(), std::forward<Ts>(ts)... );
}
这段代码创建了一个静态
的Functor::action
表,然后通过查找并调用它。
在C++03中,我们没有...
语法,所以我们必须手动完成更多的事情,也没有完美的转发。因此,我将创建一个std::vector
表代替。
首先,有一个可爱的小程序按顺序运行Functor.action<I>()
其中I在[Begin, End)之间:
template<unsigned Begin, unsigned End, typename Functor>
struct ForEach:ForEach<Begin, End-1, Functor>
};
template<unsigned Begin, typename Functor>
struct ForEach<Begin,Begin,Functor> ;
我必须承认这过于可爱了(链是由构造函数依赖项隐式创建的)。
然后我们使用它来构建一个vector
。
template<typename Signature, typename Functor>
struct PopulateVector {
std::vector< Signature* >* target;
PopulateVector(std::vector< Signature* >* t):target(t) {}
template<unsigned I>
void action() {
target->push_back( &(Functor::template action<I>) );
}
};
我们可以将这两者连接起来:
template<typename Signature, typename Functor, unsigned Max>
std::vector< Signature* > make_table() {
std::vector< Signature* > retval;
retval.reserve(Max);
PopulateVector<Signature, Functor> worker(&retval);
ForEach<0, Max>( worker ); // runtime work basically done on this line
return retval;
}
我们可以将跳转表构建为std::vector
。
然后,我们可以轻松地调用跳转表的第I个元素。
struct example_functor {
template<unsigned I>
static void action() {
std::cout << I << "\n";
}
};
void test( unsigned i ) {
static std::vector< void(*)() > table = make_table< void(), example_functor, 100 >();
if (i < 100)
table[i]();
}
当传递整数 i 时,它会打印该整数并换行。
表格中函数的签名可以是任何你想要的,因此你可以传递指向类型的指针并调用方法,其中I
是编译时常量。 action
方法必须是static
的,但它可以调用其参数的非static
方法。
C++03的主要区别在于您需要为跳转表的不同签名编写不同的代码,并且需要很多机制(以及一个std :: vector
代替静态数组)来构建跳转表。
在进行严肃的图像处理时,您将希望以这种方式生成扫描线函数,并且可能嵌入了每像素操作在生成的扫描线函数的某个地方。 除非您的图像只有1像素宽并且高达10亿像素,否则每个扫描线执行一次跳转分发通常足够快。
上述代码仍需审核确保正确性:它是未经编译的。