4

It is possible to unpack a value template parameter pack of type char into a (compile time) string. How does one acquire a string_view into that string?

What I want to do:

int main()
    {
    constexpr auto s = stringify<'a', 'b', 'c'>();
    constexpr std::string_view sv{ s.begin(), s.size() };
    return 0;
    }

Try:

template<char ... chars>
constexpr auto stringify()
    {
    std::array<char, sizeof...(chars)> array = { chars... };
    return array;
    }

Error:

15 : <source>:15:30: error: constexpr variable 'sv' must be initialized by a constant expression
constexpr std::string_view sv{ s.begin(), s.size() };
                         ^~~~~~~~~~~~~~~~~~~~~~~~~
15 : <source>:15:30: note: pointer to subobject of 's' is not a constant expression

Is there a way to get a the behaviour in the main function?

2 Answers2

3

It fails to work as constexpr because s array is located on the stack so its address is not known at compile time. To fix you can declare s as static.

Check this solution in online compiler

user7860670
  • 35,849
  • 4
  • 58
  • 84
  • Why does this compile fine then? `constexpr const char* myData = "hello"; constexpr std::string_view sv(myData);` myData is also a variable on the stack and yet it works – Valentin Nov 05 '17 at 21:33
  • 1
    @Valentin In this case data stored in globally-allocated array for string literal `"hello"`, only pointer to this array is stored on the stack. – user7860670 Nov 05 '17 at 21:36
  • That makes sense. But then how's `constexpr std::array s {'a', 'b'};` different from just `std::array s {'a', 'b'};`? What's the benefit of defining it as constexpr if you can't use it anyway? And why is it allowed? – Valentin Nov 05 '17 at 21:39
  • 1
    @Valentin It would work fine as long as you don't need the address on the stack, for example you can `constexpr auto avg{(s[0] + s[1]) / 2};` – user7860670 Nov 05 '17 at 21:43
  • Thank you very much. This was definitely one of the harder problems I encountered. –  Nov 05 '17 at 22:06
1

This code compiles in clang, though GCC still throws an (incorrect I think) error:

#include <iostream>
#include <array>
#include <string_view>

template<char... chars>
struct stringify {
    // you can still just get a view with the size, but this way it's a valid c-string
    static constexpr std::array<char, sizeof...(chars) + 1> str = { chars..., '\0' };
    static constexpr std::string_view str_view{&str[0]};
};

int main() {
    std::cout << stringify<'a','b','c'>::str_view;
    return 0;
}

Although it generates a warning about the "sub-object." (chars...) The other answer explains the reason this works.

budjmt
  • 135
  • 1
  • 9