2

Is it possible to store a string in a constexpr struct:

So far I could only come up with:

struct A
{
    constexpr A(std::string_view n): m_name(n) {}   
    constexpr auto name(){ return m_name; }

    std::string_view m_name; // This might become dangling!!
} 


which is cleary only a good idea if this class is only used like this

A a = {"Hello"};
constexpr A b = {"World"};

and not like this

auto makeA(std::string n) { return A{n}; }
A a = makeA("Hello"); // Dangling internal std::string_view

I need the constexpr to construct the struct at compile time. Is it possible to make this safer at run-time, because with std::string_view, its not.

3
  • Take a "char_sequence", Something like operator ""_cs might help. Commented Dec 31, 2019 at 10:35
  • 1
    What about making 2 similar types. One with std::string_view and one with std::string? Use the std::string_view type at compile time and the std::string type else. Maybe add an implicit conversion from compile time to run time type. Commented Dec 31, 2019 at 13:56
  • to use the constexpr you need to have in mind the very end value of the constexpr element need to be know by compiler, otherwise it can't be a const. Commented Dec 31, 2019 at 15:52

2 Answers 2

2

This is not really a question of safety as much as it is a question of semantics. Nothing prevents you from doing the exact same thing at compiletime:

constexpr A blub()
{
    char str[] = "asdf";
    return { str };
}

Since there is no way to ever call this function in a core constant expression, a program that contains code like this is ill-formed, no diagnostic required [dcl.constexpr]/5, which really isn't any better than invoking undefined behavior at runtime…

Compiletime or not, you have to ask yourself the question: Should this struct own a string or refer to an existing string? I would strongly recommend against making your struct own a string in a runtime context and refer to an existing string in a compiletime context, even if you find a way to pull this off in theory. We're talking about completely different semantics here. Completely different semantics should generally better be modeled by different types rather than one type that completeley changes its meaning depending on context…

If you want to make a constexpr struct own a string, you'll currently have to resort to some constexpr string implementation such as, e.g., this one. Since your question is tagged with , note that std::string will be useable in a constexpr context starting with C++20 [basic.string]. So, in C++20, you will be able to just have the member be an std::string

Sign up to request clarification or add additional context in comments.

1 Comment

"note that std::string will be useable in a constexpr context starting with C++20" Except that such strings cannot survive outside of a constexpr context.
1

You might do:

template<typename Char, Char... Cs>
struct CharSeq
{
    static constexpr const Char s[] = {Cs..., 0}; // The unique address
};

// That template uses the extension
template<typename Char, Char... Cs>
constexpr CharSeq<Char, Cs...> operator"" _cs() {
    return {};
}

See my answer from String-interning at compiletime for profiling to have MAKE_STRING macro if you cannot used the extension (Really more verbose, and hard coded limit for accepted string length).

Then

struct A
{
    template <char ... Cs> 
    constexpr A(CharSeq<char, Cs...>) : m_name(CharSeq<char, Cs...>::s) {}

    constexpr auto name(){ return m_name; }

    std::string_view m_name;
};

With only valid usages similar to:

A a = {"Hello"_cs};
constexpr A b = {"World"_cs};

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.