C++常量预处理宏和模板

4

假设我有以下非常简单的宏,以及一些输出该宏的代码:

#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) : error C2975: 'X' : invalid template argument for 'Printer', expected compile-time constant expression
1> .\ShiftCompare.cpp(127) : see declaration of 'X'

尽管在第一个示例中可以将SIMPLEHASH("Blah")简化为编译时常量。但是,仍然会出现上述错误。
那么问题来了,有没有一种方法告诉编译器“先评估这个”?模板在预处理器评估中自然比宏“先”吗?
有没有人看到任何我可以让这两者共同工作的方法?

1
预处理器是一个红鲱鱼。根据语言,"Blah"[0]不是一个常量表达式;就是这样。仅仅因为你的编译器碰巧能够解决它,并不意味着任何事情。(这就是采用特定于实现的结果并假设它被语言保证的问题所在。) - GManNickG
2
为了回答“我怎样才能让这两个一起工作?”这个部分,如果您能解释一下实际要解决的问题,那将会很有帮助。如果您无法“字面上”让这两个东西一起工作,您可能可以通过其他方法解决问题。 - James McNellis
尝试获取散列函数以创建别名(在编译时)以在工厂类中注册。我正在尝试为需要注册的类提供一个静态(模板类)成员,以便该成员可以在调用其构造函数时注册其所拥有的类(因为是静态的,所以立即加载代码)。显然,另一种方法是使用全局变量而不是静态成员,这样也可以正常工作,但我只是想看看是否有不留下命名空间中全局变量的方法。 - Jason
1个回答

5

宏在源代码完全解析之前被评估,预处理与模板没有任何关系。

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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接