在运行时选择正确的模板专门化
choose correct template specialization at run-time
我有
template <int i> struct a { static void f (); };
,在代码的不同位置进行特化。对于仅在运行时已知的i
,我如何调用正确的a<i>::f
?
void f (int i) { a<i>::f (); } // won't compile
我不想在一个大的switch
中列出i
的所有可能值。
我想到了
#include <iostream>
template <int i> struct a { static void f (); };
struct regf {
typedef void (*F)();
enum { arrsize = 10 };
static F v[arrsize];
template < int i > static int apply (F f) {
static_assert (i < arrsize, "");
v[i] = a<i>::f;
return 0;
}
};
regf::F regf::v[arrsize];
template <int i> struct reg { static int dummy; };
template <int i> int reg<i>::dummy = regf::apply<i> ();
void f (int i) { return regf::v[i] (); }
#define add(i)
template <> struct a<i> : reg<i> {
static void f () { std::cout << i << "n"; }
};
add(1)
add(3)
add(5)
add(7)
int main () {
f (3);
f (5);
}
但是它崩溃了(我是否错过了强制实例化的东西?),我不喜欢dummy不是static const
(并且使用内存),当然arrsize
比必要的大。
实际问题:有一个函数generate (int i)
调用a<i>::generate ()
来生成类a<i>
的实例,i
只在运行时给出。设计(类a<i>
)是给定的,它们继承自基类,并且可以在代码的任何时间任何地方添加更多的专门化,但我不想强迫每个人手动更改我的generate (i)
,因为这很容易被遗忘。
我不确定这是您可以得到的最佳解决方案,因为可能有更好的设计,无论如何,您可以使用一些元编程来触发函数的实例化和注册:
// in a single cpp file
namespace {
template <unsigned int N>
int register_a() { // return artificially added
register_a<N-1>(); // Initialize array from 0 to N-1
regf::v[N] = &a<N>::f; // and then N
return N;
}
template <>
int register_a<0>() {
regf::v[0] = &a<0>::f; // recursion stop condition
return 0;
}
const int ignored = register_a<regf::arrsize>(); // call it
}
该代码将实例化函数并注册指向静态成员函数的指针。伪返回类型需要能够在静态上下文中强制执行函数(通过使用该函数初始化静态值)。
这很容易导致静态初始化失败。虽然regf::v
是可以的,但是在静态初始化期间,任何依赖于regf::v
(包含适当指针)的代码都必然会失败。您可以使用常用的技术来改进它…
从您实际发布的点点滴滴来看,我的猜测是您正在尝试使用一个抽象工厂,并从每个具体工厂自动注册。有更好的方法来解决这个问题,但我认为这个答案解决了你的问题(我不确定这是否解决了你的问题)。
你必须这么做。模板在编译时解析和实例化。除此之外,switch
不一定是低效的。它通常编译成一个开销很小的查找表。
if/else
块,以替换编译器为您生成的switch
块。但是普通的switch
应该更具可读性。当然,除非你真的有成千上万的病例。
无论哪种情况,您都需要知道i
在编译时可以拥有的一组值,因为编译器需要知道要实例化哪些模板。
你不能在运行时选择模板特化,它们是在编译时定义的。
解决调度问题的常用方法是switch
(如您所猜测的)或int
到函数指针的vector
或map
。
不,编译器需要在编译时实例化模板,因此它需要在编译时知道i
的值
不能,因为模板实例化是在编译时完成的。
- CMake-按正确顺序将项目与C运行时对象文件链接
- 我在c++代码中生成了一个运行时#3异常
- 为什么在运行时没有向我们提供有关分段错误的更多信息?
- 删除指向指针的指针是运行时错误吗
- 如何用参数值调用函数(仅在运行时已知)
- 为什么即使使用-cudart-static进行编译,库用户仍然需要链接到cuda运行时
- 是否可以在编译时初始化数组,以便在运行时不会花费时间?
- c++中的指针和运行时错误
- 在运行时处理类型擦除的数据-如何不重新发明轮子
- 有没有一种方法可以测量c++程序的运行时内存使用情况
- 建议在运行时将带有类实例的列表从c++导入qml
- 无法理解此 return 语句的功能,没有它就会发生运行时错误
- 如何在GTK程序运行时禁用屏幕保护程序/电源管理/屏幕消隐
- 在同一模拟中使用静脉和静脉_ inet内容时出现运行时错误
- 读取文件时运行时的未知行为
- 函数在Windows或Linux上运行时表现不同
- 可以将运行时确定的模板参数传递给专门化函数吗?
- 在运行时查询模板专门化的方法/避免大的切换
- 是否有一种方法可以在编译时和运行时之间专门化一个函数
- 在运行时选择正确的模板专门化