编译时常量索引是编译时常量数组本身编译时常量吗?

时间:2009-04-20 05:21:59

标签: c++ compiler-construction metaprogramming standards-compliance

我正在尝试使用C ++编译器在编译时合成常量字符串的哈希值的花哨游戏。这将允许我用单个标识符替换字符串,大大节省了代码大小和复杂性。

为了编程清晰和简单,如果我可以在编译时检查和计算简单的内联字符串,如“Hello”,这是编译时常量字符的编译时常量指针,那就太棒了。

如果我可以在编译时索引这些,我可以制作模板元程序来做我想要的。但目前还不清楚C ++标准是否将ct常数数组的ct常量索引视为ct-constant本身。

问另一种方式,

 const char v="Hello"[0];

是非常有效的C ++(和C)。但是值v编译时间常数吗?

我已经相信答案是否定的,但实际上有些编译器在没有任何警告的情况下接受它,更不用说错误。例如,以下编译并运行,甚至没有来自英特尔C ++编译器的单一警告:

#include <iostream>
const char value="Hello"[0];
template<char c>  void printMe()
{
  std::cout << "Template Val=" << c << std::endl;
}

int main()
{
  const char v='H';
  printMe<'H'>();
  printMe<v>();
  printMe<value>(); // The tricky and interesting case!
}

但是,Microsoft的编译器根本不会编译,给出了关于将模板与具有内部链接的对象一起使用的合理连贯的错误消息。

我怀疑我的问题的答案是“不,你不能假设任何数组引用,即使是常量索引的常量数组在编译时也是常量”。这是否意味着英特尔编译器的成功执行是英特尔编译器中的错误?

3 个答案:

答案 0 :(得分:2)

它也不适用于海湾合作委员会。

然而,在语言合规性观点之外,编译器优化器确实将它视为字符常量,这很好。我利用这个事实来允许预处理器生成的字符常量(通过使用*#foo)。请参阅hdr.h文件中的http://cvs.openbsd.org/cgi-bin/query-pr-wrapper?full=yes&numbers=1652。使用该宏,您可以编写

DECR(h, e, l, l, o)

而不是

DECR('h', 'e', 'l', 'l', 'o')

在我看来,更具可读性。 : - )

答案 1 :(得分:1)

很好的问题,是的,这可以做到,并且它的标准很好,并且它可以在微软,GCC和英特尔上运行,问题是你的语法错误了:)

一秒钟我会做一个样品...... 好的,这就是。这个示例是有效的C ++,我经常使用它,但实际上大多数程序员都不知道如何正确使用它。

template<char* MSG>
class PrintMe
{
public:
    void operator()()
    {
        printf(MSG);
    }
};

char    MyMessage[6] = "Hello"; //you can't use a char*, but a char array is statically safe and determined at compiletime

int main(int argc, char* argv[])
{
    PrintMe<MyMessage> printer;
    printer();
    return 0;
}

答案 2 :(得分:0)

这里的相关差异是“积分常量表达式”与纯粹的编译时常量之间的差异。 “3.0”是编译时常量。 “int(3.0)”也是一个编译时常量。但只有“3”才是ICE。 [见5.19]

More details at boost.org