【发布时间】:2011-04-26 04:27:38
【问题描述】:
假设我有以下非常简单的宏,以及一些输出它的代码:
#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();
在视觉工作室中,这给出了:
1>.\ShiftCompare.cpp(187):错误 C2975:“X”:“打印机”的模板参数无效,预期的编译时常量表达式
1> .\ShiftCompare.cpp(127) : 见'X'的声明
尽管SIMPLEHASH("Blah") 可以在编译时减少为常量,如第一个示例所示。
那么,有什么办法可以告诉编译器“先评估这个”?在预处理器评估中,模板自然是“在”宏之前吗?
有没有人认为我可以让这两者一起工作?
【问题讨论】:
-
预处理器是一个红鲱鱼。根据语言,
"Blah"[0]不是常量表达式;而已。仅仅因为您的编译器碰巧弄明白了,这并不意味着什么。 (这就是获取特定于实现的结果并假设它由语言保证的问题。) -
回答“我怎样才能让这两者一起工作?”部分,如果您能解释您要解决的实际问题,那将会很有帮助。如果您不能真正地让这两件事协同工作,您也许可以通过其他方式解决您的问题。
-
试图让散列函数工作以创建别名(在编译时)以在工厂类中注册。我试图给需要注册的类一个静态(模板类)成员 s.t.该成员可以在调用它的构造函数时注册它的所属类(是静态的,在代码加载时立即)。显而易见的另一种方法是使用全局变量而不是静态成员,而且效果很好,我只是想看看是否有一种方法不会让全局变量在命名空间中四处乱飞。
标签: c++ templates macros c-preprocessor