问题描述
我有
template <int i> struct a { static void f (); };
在代码中的不同位置进行专门化。如何只在运行时调用 a< i> :: f 的 i >
with specializations done at different places in the code. How can I call the correct a<i>::f for an i known only at runtime?
void f (int i) { a<i>::f (); } // won't compile
我不想列出所有可能的值 i
I don't want to list all possible values of i in a big switch.
编辑:
我想到了像
#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); }
但是它崩溃了(我错过了什么来强制实例化吗?我不喜欢这个哑元不是 static const (并使用内存),当然 arrsize 大于必要。
but it crashes (did I miss something to force an instantiation?), and I don't like that dummy is not static const (and uses memory) and of course that arrsize is bigger than necessary.
实际问题:要有一个函数 generate(int i)调用 a< i> :: generate()以生成类 a 对于仅在运行时给出的 i 。给出了设计(类 a< i> ),它们继承于基类,并且可以在代码中的任何位置添加更多的特殊化,不想强迫所有人手动更改我的生成(i),因为这可能很容易被遗忘。
Actual problem: To have a function generate (int i) that calls a<i>::generate () to generate an instance of class a<i> for an i given only at run-time. The design (classes a<i>) is given, they inherit from a base class and more specializations of a could be added at any time anywhere in the code, but I don't want to force everyone to change my generate (i) manually as that could be forgotten easily.
推荐答案
我不知道这是最好的解决方案,你可以得到,因为可能有更好的设计,无论如何,你可以使用一些元编程来触发实例化和注册表的函数: / p>
I am not sure that this is the best solution that you can get, as there might be better designs, at any rate you can use some metaprogramming to trigger the instantiation and registry of the functions:
// 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 }
该代码将实例化函数和寄存器指针指向静态成员函数。伪返回类型需要能够在静态上下文中强制执行函数(通过使用该函数初始化静态值)。
That code will instantiate the functions and register pointers to the static member functions. The fake return type is required to be able to force execution of the function in an static context (by means of using that function to initialize a static value).
这是相当容易出现静态初始化fiasco。虽然 regf :: v 是确定,任何依赖于 regf :: v 的代码在静态初始化期间包含适当的指针必然失败。你可以使用通常的技巧来改善这种情况...
This is quite prone to the static initialization fiasco. While regf::v is ok, any code that depends on regf::v containing the appropriate pointers during static initialization is bound to fail. You can improve this with the usual techniques...
从你实际发布的小部件中,我猜测你正试图使用一个抽象工厂自动注册从每个混凝土工厂。有更好的方法来处理这个问题,但我认为这个答案解决了你的问题(我不确定这是否解决你的问题)。
From the bits and pieces that you have actually posted, my guess is that you are trying to use an abstract factory with automated registration from each one of the concrete factories. There are better ways of approaching the problem, but I think that this answer solves your question (I am unsure on whether this does solve your problem).
这篇关于在运行时选择正确的模板专业化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!