Reputation: 11878
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
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]
Upvotes: 0
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
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