2

这是模板规范化的代码:

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':局部变量不能用作非类型参数。任何人都可以帮助我吗?我会很感激的!

4

3 回答 3

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常量将在运行时初始化。

于 2012-06-26T23:43:29.520 回答
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变量,它试图同时成为两种类型的typeNames,有点像薛定谔的猫。编译器未能折叠波形,所以它抱怨。

于 2012-06-27T00:40:08.257 回答
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 的情况下,很难提供详细信息。

于 2012-06-27T01:06:29.263 回答