以下是模板规范的代码:
template <int i>
struct userInput{};
template <>
struct userInput<1>
{
typedef int typeName;
};
template <>
struct userInput<2>
{
typedef double typeName;
};
我想根据用户输入选择合适的模板:
int i;
std::cin>>i;
userInput<i>::typeName ty;
但是编译器对我不满意,它需要将一个传递值传递给模板参数。 所以我这样做了:
int i;
std::cin>>i;
const int p = i;
userInput<p>::typeName ty;
但是,有错误:模板参数'i':'num':局部变量不能用作非类型参数。有人可以帮帮我吗?我很感激!
答案 0 :(得分:4)
非类型模板参数需要常量的编译时表达式,因为它们在编译期间实例化:
const int x = 1;
int y = 1;
userInput<x>::typeName a; // valid
userInput<1>::typeName a; // valid
userInput<y>::typeName b; // invalid, what should be instantiated?
由于p
常量将在运行时初始化,因此无法实现您想要的操作。
答案 1 :(得分:3)
您必须在输入中switch
找到要提供给模板的常量值。
template <int i>
void foo () {
typename userInput<i>::typeName ty = 1;
std::cout << ty/2 << std::endl;
}
int i;
std::cin >> i;
switch (i) {
case 1: foo<1>(); break;
case 2: foo<2>(); break;
default: std::cerr << "invalid type: " << i << std::endl;
}
因此,如果输入为1
,则输出为0
。如果输入为2
,则输出为0.5
。对于其他人,将显示错误消息。
foo
中的代码与您尝试编写的代码之间的区别在于foo<1>
和foo<2>
是两个不同的函数,每个函数都有不同的ty
变量,每个ty
变量都有不同的类型。相比之下,您的代码有一个ty
变量,它同时尝试同时成为typeName
种,有点像Schroedinger的Cat。编译器无法折叠波形,因此抱怨。
答案 2 :(得分:1)
正如mfontanini解释的那样(并且你的编译器抱怨),非类型模板参数必须是编译时常量。而你试图通过“const int p = i;”来欺骗它没有帮助; p可以是常量变量,但它不是编译时常量。 C ++ 11编译器可以更好地告诉您这里有什么问题,但它无法帮助您解决问题。事实上,没有直接解决问题的方法。
最简单的解决方案是显式切换,如user315052所示。而且,如果你只是这样做了一次,而只是开启了1对2,那么就不值得投入更多精力了。
如果你正在多次进行切换,当然,将它包装在一个函数中是微不足道的:
void bar(int i) {
switch(i) {
case 1: foo(userInput<1>::typeName()); return;
case 2: foo(userInput<2>::typeName()); return;
default: throw someException;
}
但是如果你有超过2个案例,或者这些值不断变化,那么你肯定会想要使用Boost.Preprocessor自动化这个例子:
#define FOO_CASES_ 50
#define FOO_PASTE_(rep, i, _) case i: foo(userInput< i >::typeName()); return;
void bar(int i) {
switch (i) {
BOOST_PP_REPEAT(FOO_CASES_, FOO_PASTE_, _)
default: throw someException;
}
}
#undef FOO_CASES_
#undef FOO_PASTE_
或者,或者,编写一个代码生成器,创建一个.cpp文件供您编译:
#!/usr/bin/env python
with file('bar.cpp', 'w') as f:
f.write('void bar(int i) {\n')
f.write(' switch(i) {\n')
for i in range(50):
f.write(' case %d: foo(userInput<%d>::typeName()); return;\n' % (i, i))
f.write(' default: throw someException;\n')
f.write(' }\n')
f.write('}\n')
另一个替代方法是创建一个使用适当的对象/函数/任何东西初始化的查找数组(或向量),这样就可以使用* userInputLookup [i]代替userInput。但是,如果不知道确切的用例,以及您是否使用C ++ 11,则很难提供详细信息。