2010-10-15 109 views
3

所以说我有一个位的代码输出下面很简单的宏,沿着它:C++恒预处理宏和模板

#define SIMPLEHASH(STRING) STRING[1] + STRING[2] + STRING[3] 
std::cout << SIMPLEHASH("Blah"); 

这个输出309,如果你查看装配就可以看到:

00131094 mov   ecx,dword ptr [__imp_std::cout (132050h)] 
0013109A push  135h 
0013109F call  dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (13203Ch)] 

其中135h很好地翻译成309十进制。一切都被编成了一个常数。


现在,假设你有一个模板类这样:

template<int X> class Printer{ 
public: 
void Print(){ 
    std::cout << X; 
} 
}; 

那么下面将很好地打印数32:这两个东西单独工作

Printer<32> p; 
p.Print(); 

,当您尝试将它们合并时,问题就出现了:

#define SIMPLEHASH(STRING) STRING[1] + STRING[2] + STRING[3] 
Printer<SIMPLEHASH("Blah")> p; 
p.Print(); 

在Visual Studio这给出:

1> \ ShiftCompare.cpp(187):错误C2975: 'X':为 '打印机' 无效模板参数,预期编译时间常量表达式
1> \ ShiftCompare.cpp(127):参见“X”

的声明尽管SIMPLEHASH("Blah")可以降低到在编译时的常数,如在第一实施例所示。

那么,有什么办法可以告诉编译器“先评估这个”?模板在预处理器评估中自然地位于“宏”之前?

有没有人看到任何方式我可以让这两个一起工作?

+1

预处理器是一个红色的鲱鱼。根据该语言,“Blah”[0]不是一个常量表达式;而已。仅仅因为你的编译器偶然发现并不意味着什么。 (这是针对特定实现的结果的问题,并且假设它是由语言保证的。) – GManNickG 2010-10-15 22:33:35

+2

回答“我怎样才能让这两个人一起工作?”部分,如果你能解释你正在试图解决的实际问题,这将是有帮助的。如果你无法一起获得这两件事情,那么你可以通过其他方式解决你的问题。 – 2010-10-15 22:35:48

+0

试图让hashing函数在工厂类中创建别名(在编译时)以进行注册。我试图给需要注册的类是一个静态(模板类)成员s.t.该成员可以在构造函数被调用时将其注册为拥有类(静态,立即在代码加载时)。显而易见的另一种方式是使用全局变量而不是静态成员,而且工作正常,我只是想看看是否有一种方法不会让全局变量在命名空间中飞行。 – Jason 2010-10-15 23:13:24

回答

5

在源文件完全解析和预处理完全没有任何与模板有关的事情之前,对宏进行评估。

问题是,您实例化的模板参数Printer必须是常量表达式,并且不能在常量表达式中使用字符串常量。