0

I'm trying to provide a template argument with a const char* argument. My understanding is that you can provide a template argument with essentially an address, such as a function pointer and stuff like that. In this case I'd like to give it a pointer to an address holding a string, or char array, but it doesn't work:

constexpr const char* pString = "hello";
constexpr int* pToInt = nullptr;
// Am I right to have constexpr const char*? The constexpr says the pointer is const
// And the const before the char says the char is unmodifiable?

template <int* pToInt>
class TakeStaticIntPointer
{};

template <const char* pToString>
class TakeStaticStringPointer
{};

int main()
{
    TakeStaticIntPointer<pToInt> myFoo; // Works fine

    TakeStaticStringPointer<pString> myFoo2;
// Invalid non-type template argument of type const char*
}

I don't understand what's going on here. I'd also like to provide the template argument of a string literal "Hello". That's a compile-time constexpr, isn't it?

Zebrafish
  • 11,682
  • 3
  • 43
  • 119
  • [cppreference / Template non-type arguments](https://en.cppreference.com/w/cpp/language/template_parameters): "For pointers to objects, the template arguments have to designate the address of a complete object with static storage duration and a linkage [...] In particular, this implies that string literals, addresses of array elements, and addresses of non-static members cannot be used as template arguments to instantiate templates whose corresponding non-type template parameters are pointers to objects." – dfrib Aug 30 '21 at 15:13
  • 4
    While a string literal stands for a static array of characters, it is too "floaty". A compiler can replace all literals by the same array, or there can be different arrays for each literal appearance. In some implementations `"a\0b"` and `"a"` can share an address. And the same is true across TU's. Since the template arguments are baked into the linkage of templated entities, such "floatiness" is an ODR nightmare. So it's simply verboten. – StoryTeller - Unslander Monica Aug 30 '21 at 15:15
  • As for `// Am I right to have constexpr const char*?` yes you are right. See [Is const keyword mandatory while declaring"constexpr char\*" string?](https://stackoverflow.com/a/68751807) – mediocrevegetable1 Aug 30 '21 at 15:33

1 Answers1

0

Unfortunately constexpr const char* Patting = "hello";, the address of a string literal is not a constexpr. Assignments of string literals and getting their addresses happen at link time, not at compile time. The solution with a real constexpr is like below.

constexpr const char pString[] = "hello";
constexpr int* pToInt = nullptr;
// Am I right to have constexpr const char*? The constexpr says the pointer is const
// And the const before the char says the char is unmodifiable?

template <int* pToInt>
class TakeStaticIntPointer
{};

template <const char* pToString>
class TakeStaticStringPointer
{};

int main()
{
    TakeStaticIntPointer<pToInt> myFoo; // Works fine

    TakeStaticStringPointer<pString> myFoo2; // Works fine with char[6]
}
273K
  • 29,503
  • 10
  • 41
  • 64
  • What does that do? To make it a char array instead of a char pointer? – Zebrafish Aug 30 '21 at 15:33
  • This makes the C-string array instead of the address of the string literal. The first one is a constexpr, the second one is the address of a string literal and is not a constexpr. – 273K Aug 30 '21 at 15:55