Home > Back-end >  Compile surprises on using an string as a template argument
Compile surprises on using an string as a template argument

Time:12-22

So, I was playing with strings in templates, I saw some interesting blogs and started playing with. In the next example, I was able to pass a string literal in a template argument.

#include <algorithm>
#include <iostream>

template<size_t N>
struct StringLiteral {
    constexpr StringLiteral(const char (&str)[N]) {
        // commenting this makes the program to not compile
        std::copy_n(str, N, value);
    }
    constexpr size_t size() const
    {
        return N;
    }

    // changing N to literal, such as 10, makes the program to not compile
    char value[N];
};

template<StringLiteral lit>
void Print() {
    static constexpr auto size = lit.size();
    static constexpr auto contents = lit.value;

    std::cout << "Size: " << size << ", Contents: " << contents << std::endl;
}

int main()
{
    Print<"abc">();
}

Godbolt Link

In this example, I'm passing a string to Print by a template parameter, and, it will print the size and value, so far so good.

However, I'm using some features that I don't fully understand, that's probably why I'm so confused.

  1. If I remove std::copy_n, it doesn't compile. That was very surprising because that code is inside the constructor, N just be deduced before, so, I'm not sure why copy_n had these implcations.
  2. Changing char value[N] to char value[10] also makes the program invalid, 10 it's a literal, I was expecting the compiler would be able to deduce it without a problem.

Could you clarify what's going on?

CodePudding user response:

Both error are caused by value remaining partially uninitialized. Adding {} to zero all elements by default is one way to solve this: char value[N]{};.

CodePudding user response:

When you work with classes in a constexpr context, it is important to guarantee the initialization.

You don't need to set a value, but at least saying : value() will make it clear that the members is initialized.

constexpr StringLiteral(const char (&str)[N]) : value() {
        
}

If you let the constructor empty without the : value(), you leave value unitialized, which causes problems within the constexpr context.

  • Related