Home > Back-end >  Why can an array of char be a template parameter but a const char* can't
Why can an array of char be a template parameter but a const char* can't

Time:05-26

I'm trying to pass a literal string as a template parameter in a C 14 project. Google told me that I can do as below:

struct Test {
    static const char teststr[];

    template<const char* str>
    void p() {std::cout << str;}
};

const char Test::teststr[] = "Hello world!";

int main() {
    Test t;
    t.p<Test::teststr>();
}

It did work.

However, if I use const char*, instead of const char []. It won't work.

struct Test {
    static const char* teststr;

    template<const char* str>
    void p() {std::cout << str;}
};

const char* Test::teststr = "Hello world!";

int main() {
    Test t;
    t.p<Test::teststr>();
}

Now it doesn't work. The compiler told me that 'Test::teststr' is not a valid template argument because 'Test::teststr' is a variable, not the address of a variable.

Well, I don't know what it meant.

CodePudding user response:

This is just according to the rules of c :

Template non-type arguments.
For pointers to objects, the template arguments have to designate the address of a complete object with static storage duration and a linkage (either internal or external)

https://en.cppreference.com/w/cpp/language/template_parameters

A global array of characters has linkage while a string literal doesn’t.
In C 20 this has been changed and you can use string literals as template parameters.

CodePudding user response:

The error message from the compiler is clear enough:

error: 'Test::teststr' is not a valid template argument because 'Test::teststr' is a variable, not the address of a variable

So you need:

#include <iostream>

struct Test {
    static const char* teststr;

    template<const char **str>
    void p() {std::cout << *str;}
};

const char* Test::teststr = "Hello world!";

int main() {
    Test t;
    t.p <&Test::teststr>();
}

And then it works - the point being that [the contents of] a variable is not a compile-time constant, whereas the address of a variable is.

CodePudding user response:

The problem is that in case 2 of your example the static data member teststr is a pointer type that has the address of a string literal which is not allowed by the standard as can be seen from the quoted statement below ,

From non-type template parameter's documentation:

A template-argument for a non-type template-parameter shall be a converted constant expression (5.20) of the type of the template-parameter. For a non-type template-parameter of reference or pointer type, the value of the constant expression shall not refer to (or for a pointer type, shall not be the address of):

  • (1.1) a subobject (1.8),

  • (1.2) a temporary object (12.2),

  • (1.3) a string literal (2.13.5),

Thus, in case 2 of your example teststr cannot be used as it is a pointer type that has the address of the string literal "Hello world!".


  • Related