SPWorley
SPWorley

Reputation: 11878

Is a compiletime constant index into a compiletime constant array itself compiletime constant?

I am trying to play fancy games which have the C++ compiler synthesize hash values of constant strings at compiletime. This would let me replace the string with a single identifier, with a massive savings in code size and complexity.

For programming clarity and ease, it'd be awesome if I could examine and compute at compiletime with simple inline character strings like "Hello" which are compiletime constant pointers to compiletime constant chars.

If I can index into these at compiletime, I can make a template metaprogram to do what I want. But it is unclear if the C++ standard treats a ct-constant index of a ct-constant array as ct-constant by itself.

Asked another way,

 const char v="Hello"[0];

is quite valid C++ (and C). But is the value v a compile time constant?

I already believe the answer is no, but in practice some compilers accept it without even any warning, much less error. For example, the following compiles and runs without even a single warning from Intel's C++ compiler:

#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!
}

However, Microsoft's compiler will not compile at all, giving a reasonably coherent error message about using a template with an object with internal linkage.

I suspect the answer to my question is "No, you can't assume any array reference even to a constant array with a constant index is constant at compiletime". Does this mean the Intel compiler's successful execution is a bug in the Intel compiler?

Upvotes: 2

Views: 1299

Answers (3)

MSalters
MSalters

Reputation: 179867

The relevant difference here is the difference between a "Integral Constant Expression" and a mere compile-time constant. "3.0" is a compile-time constant. "int(3.0)" is a compile-time constant, too. But only "3" is an ICE. [See 5.19]

More details at boost.org

Upvotes: 0

Robert Gould
Robert Gould

Reputation: 69855

Good question, yes this can be done, and its fine with the standards, and it'll work on Microsoft, GCC, and Intel, problem is you have the syntax wrong :)

One second I'll cook up a sample... Ok done, here it is. This sample is valid C++, and I've used it quite often, but indeed most programmers don't know how to get it right.

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;
}

Upvotes: 1

C. K. Young
C. K. Young

Reputation: 223023

It doesn't work on GCC either.

However, outside of a language-compliance viewpoint, it's nice that the compiler optimiser does treat it as a character constant, pretty much. I exploited that fact to allow preprocessor-generated character constants (by using *#foo). See http://cvs.openbsd.org/cgi-bin/query-pr-wrapper?full=yes&numbers=1652, in file hdr.h. With that macro, you could write

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

rather than

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

Much more readable, in my view. :-)

Upvotes: 2

Related Questions