使用int作为直到运行时才知道的模板形参
Using an int as a template parameter that is not known until run-time
我试图使用一个整数作为一个类的模板参数。下面是一个示例代码:
template< int array_qty >
class sample_class {
public:
std::array< std::string, array_qty > sample_array;
}
如果我这样做,它会工作:
sample_class< 10 > sample_class_instance;
然而,假设我在编译时不知道array_qty(模板参数)的值,只在运行时知道。在这种情况下,我将传递一个int变量作为模板参数。为了便于演示,下面的代码不起作用:
int test_var = 2;
int another_test_var = 5;
int test_array_qty = test_var * another_test_var;
sample_class< test_array_qty > sample_class_instance;
在编译时,我得到以下错误,当尝试上面的:
the value of ‘test_array_qty’ is not usable in a constant expression
我已经尝试将test_array_qty转换为const,同时将其作为模板参数传递,但这似乎也不起作用。有什么方法可以做到这一点,还是我滥用模板参数?也许它们需要在编译时就知道?
我们的目标不是解决这个特定的方法,而是找到一种方法,将数组的长度设置为一个int变量,可以在实例化类时声明。如果有办法通过模板参数来实现这一点,那将是理想的。
请注意,我必须使用一个数组,而不是一个向量,我可能最终作为一个建议。此外,array_qty将始终是0到50之间的值——以防产生差异。
这是可以做到的。但请相信我,你问错了问题。因此,下面的内容回答了你的问题,尽管这样做几乎总是一个坏主意。
你实际上可以做的是创建50个不同的程序,每个程序对应50种可能的大小,然后有条件地跳转到你想要的那个。
template<int n>
struct prog {
void run() {
// ...
}
};
template<int n>
struct switcher {
void run(int v) {
if(v==n)
prog<n>::run();
else
switcher<n-1>::run(v);
}
};
template<>
struct switcher<-1> {
void run(int v){
}
};
调用switcher<50>::run( value );
,如果value为0 ~ 50,则调用prog<value>::run()
。在prog::run
中,模板参数是编译时的值。
可怕的黑客,你可能会更好地使用另一个解决方案,但这是你所要求的。
下面是c++ 14基于表的版本:
template<size_t N>
using index_t = std::integral_constant<size_t, N>; // C++14
template<size_t M>
struct magic_switch_t {
template<class F, class...Args>
using R=std::result_of_t<F(index_t<0>, Args...)>;
template<class F, class...Args>
R<F, Args...> operator()(F&& f, size_t i, Args&&...args)const{
if (i >= M)
throw i; // make a better way to return an error
return invoke(std::make_index_sequence<M>{}, std::forward<F>(f), i, std::forward<Args>(args)...);
}
private:
template<size_t...Is, class F, class...Args>
R<F, Args...> invoke(std::index_sequence<Is...>, F&&f, size_t i, Args&&...args)const {
using pF=decltype(std::addressof(f));
using call_func = R<F, Args...>(*)(pF pf, Args&&...args);
static const call_func table[M]={
[](pF pf, Args&&...args)->R<F, Args...>{
return std::forward<F>(*pf)(index_t<Is>{}, std::forward<Args>(args)...);
}...
};
return table[i](std::addressof(f), std::forward<Args>(args)...);
}
};
magic_switch_t<N>{}( f, 3, blah1, blah2, etc )
将调用f(index_t<3>{}, blah1, blah2, etc)
。
一些c++ 14编译器会阻塞包含lambda的可变包展开。这不是必须的,你可以做一个变通,但变通是丑陋的。
c++ 14的所有特性都是可选的:你可以在c++ 11中实现它们,但是还是很难看。
传递的f
基本上应该是一个函数对象(以auto
作为第一个参数的lambda,或手动的)。直接传递函数名不能很好地工作,因为当第一个参数成为编译时值时,上面的方法最有效。
你可以用lambda或函数对象来包装函数模板。
对于c++ 11,非类型模板参数被限制为以下(§14.3.2/1):
非类型、非模板模板形参的模板实参必须是:
- 对于整型或枚举型的非类型模板形参,为模板形参类型的转换常量表达式(5.19);或
- 非类型模板参数的名称;或
- 一个常量表达式(5.19),它指定具有静态存储时间和外部或内部链接的对象的地址,或具有外部或内部链接的函数的地址,包括函数模板和函数模板id,但不包括非静态类成员,表示为(忽略括号)&id-表达式,除了&引用函数或数组的可以省略,引用模板形参的可以省略;或
- 一个计算结果为空指针值的常量表达式(4.10);或
- 计算结果为空成员指针值的常量表达式(4.11);或
- 5.3.1中描述的成员指针。
在c++ 98和c++ 03中,列表的限制更大。底线是:你想做的事情是不被允许的。
模板参数必须是编译时常量,即"常量表达式"或简称constexpr
s。所以没有办法做的就是使用模板。
可以使用动态大小的数组,并将其大小存储在int
中。
或者简单地使用vector
。一定要在构造函数中通过将所需的大小传递给vector的构造函数来初始化它的大小!
对不起,这是不可能的。模板参数必须是编译时已知的常量表达式。
我有点晚了,但这是我的建议。我猜矢量的主要问题是,它们分配的容量比支持动态增长所需的容量大。那么,您就不能编写自己的简单数组类吗?
template <typename T>
class Array {
private:
T* data;
unsigned size;
public:
Array(unsigned size) {
data = new T[size];
this->size = size;
}
T& operator[](int i) {
return data[i];
}
T operator[](int i) const {
return data[i];
}
// Depending on your needs, maybe add copy constructor and assignment operator here.
...
unsigned size() {
return size;
}
~Array() {
delete [] data;
}
}
据我所知,我相信这应该和STL数组类一样快。此外,您可以创建在运行时之前大小未知的数组,数组的内存在销毁时自动处理,并且您不必每次创建具有不同大小的新数组时都实例化一个新类(就像您必须为STL数组所做的那样)。
- CMake-按正确顺序将项目与C运行时对象文件链接
- 我在c++代码中生成了一个运行时#3异常
- 为什么在运行时没有向我们提供有关分段错误的更多信息?
- 删除指向指针的指针是运行时错误吗
- 如何用参数值调用函数(仅在运行时已知)
- 为什么即使使用-cudart-static进行编译,库用户仍然需要链接到cuda运行时
- 是否可以在编译时初始化数组,以便在运行时不会花费时间?
- c++中的指针和运行时错误
- 在运行时处理类型擦除的数据-如何不重新发明轮子
- 有没有一种方法可以测量c++程序的运行时内存使用情况
- 模板(C++)中的参数值:可以在运行时指定吗?
- 如何在编译时通过模板形参默认值的名称/指针获取函数的类型
- 使用模板模板形参时,模板实参推导失败
- 如何在boost中使用boost::ref.传递参数时的形参库
- c++ 03:是否有一种方法可以使一个类型每次被包含在模板形参中时都会编译成不同的类型?
- 为什么这样调用构造函数时模板形参推导失败?
- 启用基于类模板形参的构造函数时,是否总是需要复制该类模板形参?
- c++:当使用结果作为成员函数的形参时,关于转换构造函数的混淆
- 在类模板中访问enum时避免重复使用模板形参
- 使用int作为直到运行时才知道的模板形参