views:

343

answers:

6

Can strings be used as template arguments?

I tried:

template <char *str>
struct X
{
    const char *GetString() const
    {
         return str;
    }
};

int main()
{
    X<"String"> x;
    cout<<x.GetString();
}

And although I get no complaints about the class definition, the instantiation yeilds 'X' : invalid expression as a template argument for 'str' (VC).

+2  A: 

No, you can't work with string literals at compile time. The best you can get are the weird multicharacter literals (e.g. 'abcd') which some compile-time parsers use. They are mentioned in §2.13.2.1:

An ordinary character literal that contains more than one c-char is a multicharacter literal. A multicharac- ter literal has type int and implementation-defined value.

In C++0x there might be ways around this limitations though with the new string literals, Arctic Interactive has an interesting article on that.

Georg Fritzsche
Can you expand of these "weird 4-character-literals"?
cvb
Added to the answer, don't have the compile-time parser article which uses them handy though.
Georg Fritzsche
+3  A: 

A string literal cannot be used as a template argument.

This would work, however:

template <char const *str>
struct X
{
    const char *GetString() const
    {
         return str;
    }
};

char global_string[] = "String";

int main()
{
    X<global_string> x;
    cout<<x.GetString();
}
moonshadow
This doesn't seem to work, global_string doesn't evaluate to a compile time constant.
Andreas Brinck
I think you want to do `char global_string[] = "String";`. The way you have it now has two problems: You are trying to get rid of "const", and you cannot pass the *value* of that pointer. You have to pass the *address* of the object. (but for that pointer, it would have type `char const**` - thus you need to do it another way, for instance using an array - the address-of operator is optional for an array or function here).
Johannes Schaub - litb
@Johannes: true. Edited. Teach me to answer without doing a test compile.
moonshadow
+3  A: 

Take a look at this:

Comeau C++ Template FAQ: How can I pass a "string literal" to a template?

skwllsp
A: 

C++ does not know about strings. It only knowns about "arrays of characters" and there the literal would be the pointer to the array. So if you would use the "value" of your string as template parameter you would actually use the pointer value.

ctron
This is also wrong. A string literal is an array of constant characters, which is perfectly valid as a template argument. But the problem is the literal has internal linkage.
Johannes Schaub - litb
+2  A: 

No. According to C++ Standard 14.3.2/1:

A template-argument for a non-type, non-template template-parameter shall be one of:
— an integral constant-expression of integral or enumeration type; or
— the name of a non-type template-parameter; or
— the address of an object or function with external linkage, including function templates and function template-ids but excluding non-static class members, expressed as & id-expression where the & is optional if the name refers to a function or array, or if the corresponding template-parameter is a reference;or
— a pointer to member expressed as described in 5.3.1 .

Strings are not in the list.

Kirill V. Lyadvinsky
A: 

You can use address of string with external linkage as a template parameter, e.g.:

template <const char** T> class My {
public:
    void do_stuff() {
      std::cout << "zzz";
    }
};

const char* str;

int main()
{
  My<&str> zz;
    zz.do_stuff();

    printf("Result: %d %d \n",  60 % 10 + 1, (60 % 10 ) + 1 );
}

corvus