【发布时间】:2015-11-28 22:05:19
【问题描述】:
我在命名空间 N 中有一个类 C,其公共模板成员函数 F 如下:
namespace N {
class C {
public:
template<int I>
void F() {
// ...
}
};
};
N::C::F<I> 的 I 的值直到运行时才知道。但是,I 的值受到限制,使得0 <= I < 2^8。我正在寻找一种方法来强制此函数将模板扩展到所有 256 种可能的形式。
到目前为止,我已经在 C 的第二个函数中手动创建了一个静态数组,它指向每个可能的函数:
template<int I>
void F() {
// ...
}
void G(int I) {
static void(* const funcs[256])() = {
F<0>, F<1>, F<2>, ...
};
funcs[I]();
}
虽然我想知道是否有更好的方法。我已经在N 中有一个宏,它负责为I 的每个值构造一个单独的结构(供F 本身使用),并且正在寻找是否可以在其中以某种方式集成模板成员函数的实例化:
template<int> struct S;
#define M(I, n) \
template<> struct S<I> { \
static const char name[] = #n; \
/*
Some how instantiate the function here, like (just guessing here):
static const SEvaluator<I> eval = &C::F<I>;
given
template<int I>
using SEvaluator = void(*)();
*/
};
M(0, "foo"); M(1, "bar");
#undef M
我提出的方法不能按原样工作,编译器抱怨 F 不是 constexpr。 F 操作C 的几个变量并调用外部方法,无法声明为 constexpr。有没有办法挽救这个问题,还是我必须求助于我的第一个黑客方法?
【问题讨论】:
-
有点绕你的问题,但
I不能只是一个普通的函数参数吗?通过生成 256 个函数版本并支付间接分支的成本(在运行时确定实际值时这是不可避免的),我看不到您可能获得的太多好处,只是为了允许基于已知的I进行一些优化编译时间。它似乎是用更小的开销换取更大的开销。就像F中的手动展开循环一样?那种东西应该更直接,并带来更多的回报。 -
@Ike 对于上下文,
F执行各种操作码I的逻辑。虚拟机将遍历 ROM 并在当前字节上调用F。 F 由一堆 if 语句组成,检查给定的I是否具有给定的寻址模式、功能等。目前我有这些 if 语句都针对每个操作码进行程序评估,但我认为将逻辑划分为单独的分支-less 函数和创建跳转表会带来性能提升。 (1/2) -
如果我理解正确的话,就性能而言,拥有更多函数的二进制开销和额外间接分支的评估开销将超过评估一堆不必要的 if 语句的开销。我不能说我对低级优化有很多了解,所以这种方法至少在我的脑海中是有意义的,但是你建议我如何改进呢? (2/2
-
我明白了——如果你正在有效地模拟一个跳转表并且为
F生成的代码本质上是相对较小和/或非常多枝的(内部有很多if/else),它可能非常值得寻求这个。我有点担心的只是这个跳转表的大小和生成的潜在代码量以及内联功能的潜在损失(如果F很小)或 icache 问题(如果F很大)-我们可能会失去比我们在那里获得的更多。我很好奇它的表现如何——这是一个非常有趣的例子,更多的代码和一个广泛的分支与更少的代码和更小的分支。
标签: c++ templates c++11 instantiation