Sign in to follow this  
_moagstar_

Accessing the characters of a string literal at compile time?

Recommended Posts

Hi, I would like to know if there is any way that I can get access to the characters of a string literal at compile time for use as template parameters. I have written some template classes for generating CRC's at compile time from an input string, the problem is that you have to pass the string in like this

unsigned int crc = CCompileTimeCRC6<'s','t','r','i','n','g'>::value;



Which isnt the nicest way of specifying a string. I really want to be able to access the individual characters in a string literal, something like this :

#define CRC3(STRING) CCompileTimeCRC3<STRING[0], STRING[1], STRING[2]>::value

unsigned int crc = CRC3("abc");



etc. But unfortunately the compiler does not see these as compile time values. Does anyone have any ideas, is it possible in any way to specify a string literal like this and access the individual chars to pass as template arguments (or set as enum values, or array sizes?)

Share this post


Link to post
Share on other sites
You can get around it for short strings by using something like this:
__int64 nString = 'foobar';
However, that limits you to 8 letters (64 bits).

Share this post


Link to post
Share on other sites
That doesn't compile for me (VS2005), first of all I get this :


error C2015: too many characters in constant


So I change to :


const __int64 = (const __int64)"foobar";


And I get :


error C2971: a local variable cannot be used as a non-type argument


So I moved the variable to a global :


error C2970: an expression involving objects with internal linkage cannot be used as a non-type argument


So I externed it and I get this :


error C2975: invalid template argument, expected compile-time constant expression


grrrr... For crying out loud c++, all the information you need is there at compile time ;)

It was a good effort though, thanks for you're input. It's a shame you can't do something like :

CCompileTimeCRC6<const __int64("foobar")>::value

Share this post


Link to post
Share on other sites
Yep that works



template <int string>
class Test
{
public:
enum
{
value = string;
}
};

const int temp = 'test';
int b = Test< temp >::value;




Although I think the 4 character limit might be a problem ;) Although it's probably easier to specify things in terms of four character groups than 1 character at a time, so it's a start.

Thanks, it's very frustrating because it's a string literal, it's there at compile time, does any one know why you can't access the individual characters? It seems bizzare to me.

Share this post


Link to post
Share on other sites
Might it be that a (null-terminated) string is stored as the address of the first character? This makes accessing any other characters a (albeit small) calculation which is something that is done at runtime and not at compile time.

PS: it is just a totally wild guess; I'm not much into these things so I might just have said something stupid.
(hmz the storage pointer thing might not hold for literals...)

Greetz,

Illco

Share this post


Link to post
Share on other sites
Actually I think you're right, the string literals are (depending on compiler settings) stored in read-only memory at runtime, so it kind of makes sense.

But it's a little frustrating that the data is all there and present at compile time, you just can't get to it. I guess it's something I'm going to have to live with.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Did you recently post the same question at c.l.c++.m? If not, there is a long (but interesting) thread posted there on the same subject.

Sorry about posting Anonymous. My password was reset but my screen name (mfawcett) was registered with a previous (and now unaccessible) e-mail address.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Hm, it appears my HTML got stripped. Here's the link in copy/paste form:

http://groups.google.com/group/comp.lang.c++.moderated/browse_frm/thread/5ff993d820cb3006/#

Share this post


Link to post
Share on other sites
Quote:
Original post by _moagstar_
    #define CRC3(STRING) CCompileTimeCRC3<STRING[0], STRING[1], STRING[2]>::value
unsigned int crc = CRC3("abc");
But unfortunately the compiler does not see these as compile time values.

Are you sure? This code compiles and runs for me on VS 2005.

#include "stdafx.h"
#include <iostream>

int main(int argc, char* argv[])
{
std::cout << "hello world"[0];
std::cout << "hello world"[1];
std::cout << "hello world"[2];
std::cout << "hello world"[3];
std::cout << "hello world"[4];
std::cout << "hello world"[5];
std::cout << "hello world"[6];
std::cout << "hello world"[7];
std::cout << "hello world"[8];
std::cout << "hello world"[9];
std::cout << "hello world"[10];
std::cout << std::endl;
return 0;
}


Share this post


Link to post
Share on other sites
Quote:
Original post by JohnBolton
Quote:
Original post by _moagstar_
    #define CRC3(STRING) CCompileTimeCRC3<STRING[0], STRING[1], STRING[2]>::value
unsigned int crc = CRC3("abc");
But unfortunately the compiler does not see these as compile time values.

Are you sure? This code compiles and runs for me on VS 2005.


Keywords bolded. Your example is inconsequential, given that std::cout works just fine with runtime values.

Here's a working demonstration example of the problem:

template < char C > struct foo {};

int main() {
foo< 'a' > f1; //compiles fine
foo< "a"[0] > f2; //error C2975: 'C' : invalid template argument for 'foo', expected compile-time constant expression (MSVC 8.0, SP0)
}


EDIT: Of course, the optimizer of any given compiler is probably smart enough for the compiler to determine the value of the expression at compile time, but sadly this alone is not enough to meet the C++ standard's requirements for a "compile-time constant expression".

[Edited by - MaulingMonkey on March 10, 2007 12:43:28 AM]

Share this post


Link to post
Share on other sites
Quote:
Original post by MaulingMonkey
Quote:
Original post by JohnBolton
Quote:
Original post by _moagstar_
    #define CRC3(STRING) CCompileTimeCRC3<STRING[0], STRING[1], STRING[2]>::value
unsigned int crc = CRC3("abc");
But unfortunately the compiler does not see these as compile time values.

Are you sure? This code compiles and runs for me on VS 2005.


Keywords bolded. Your example is inconsequential, given that std::cout works just fine with runtime values.

Hmm. I should have tried it with this specific case. I guess "abc"[0] is too clever for the compiler, or that it doesn't consider it a constant expression because it stores "abc".

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
Original post by JohnBolton
I guess "abc"[0] is too clever for the compiler
Wrong reasoning. The compiler may well be smart enough to figure it out as a compile-time constant, but it doesn't matter; The C++ standard mandates the behaviour, which is to fail independent of the compiler's cleverness.

Share this post


Link to post
Share on other sites
Quote:
Original post by Anonymous Poster
Quote:
Original post by JohnBolton
I guess "abc"[0] is too clever for the compiler
Wrong reasoning. The compiler may well be smart enough to figure it out as a compile-time constant, but it doesn't matter; The C++ standard mandates the behaviour, which is to fail independent of the compiler's cleverness.


Again, bingo.

Example disassembly (MSVC8 SP0):
int main() {
std::cout << "a"[0] << "b"[0] << std::endl;
00401000 mov eax,dword ptr [__imp_std::endl (402038h)]
00401005 mov ecx,dword ptr [__imp_std::cout (402054h)]
0040100B push eax
0040100C push 62h ; ASCII 'b'
0040100E push 61h ; ASCII 'a'
00401010 push ecx
00401011 call std::operator<<<std::char_traits<char> > (401160h)
00401016 add esp,8
00401019 push eax
0040101A call std::operator<<<std::char_traits<char> > (401160h)
0040101F add esp,8
00401022 mov ecx,eax
00401024 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (402040h)]
}


For those wondering why I've used two strings, it is because the optimizer seems to have spirited away my constant to places unknown the operator<< implementation with only one.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this