204

Using C++11, Ubuntu 14.04, GCC default toolchain.

This code fails:

constexpr std::string constString = "constString";

error: the type ‘const string {aka const std::basic_string}’ of constexpr variable ‘constString’ is not literal... because... ‘std::basic_string’ has a non-trivial destructor

Is it possible to use std::string in aconstexpr? (apparently not...) If so, how? Is there an alternative way to use a character string in a constexpr?

Vector
  • 8,941
  • 10
  • 52
  • 96
  • 5
    `std::string` is not a literal type – Piotr Skotnicki Nov 25 '14 at 09:47
  • 11
    @PiotrS - the question says that... – Vector Nov 25 '14 at 09:48
  • @Vector only literal types can be made `constexpr`. why do you need `std::string` to be constexpr? maybe there is alternative solution – Piotr Skotnicki Nov 25 '14 at 09:51
  • @PiotrS. I assume that excludes user-defined or library defined literals like `std::string_literals::operator""s` that return types with non-trivial destructors – PeterT Nov 25 '14 at 10:12
  • 1
    @PiotrS - yes, again, I understood the error message. Why? Why does anyone **need** a constexpr? We did just fine without it. It's an optimization. Also see: [When should you use constexpr capability in C++11?](http://stackoverflow.com/questions/4748083/when-should-you-use-constexpr-capability-in-c11) – Vector Nov 25 '14 at 10:18
  • 6
    @Vector did I ask you what the constexpr is for or why do you want `std::string` to be constexpr? there are several compile-time string implementations on SO. what is the point in asking if you can make a non-literal type constexpr if you understand error message and know only literal types can be made constexpr? as well there are several reasons why one may want to have a constexpr instance, so I suggest you clarify your question – Piotr Skotnicki Nov 25 '14 at 10:25
  • I agree with @PiotrS.; you already know `std::string` is impossible as `constexpr`, so obviously you *don't* need this. The next best thing is to explain what you're trying to accomplish, otherwise the default answer is to just use string literals like in my answer. – tenfour Nov 25 '14 at 10:38
  • @PiotrS. - Clarified. – Vector Nov 25 '14 at 11:06
  • 1
    @tenfour - _impossible_ - the error message says _non-trivial destructor_ - I was wondering if there was a way to circumvent or implement an alternative to that destructor in a relatively safe and painless way, so it would be _trivial_. But I suppose that would mean writing my own string class... – Vector Nov 25 '14 at 11:11
  • 4
    Yes as @PiotrS. said, there are `constexpr` string implementations out there. `std::string` is not one of them. – tenfour Nov 25 '14 at 11:12
  • 4
    @PiotrS - _there are several compile-time string implementations on SO_ - OK, thanks, understood. That's not an option for me but it answers my question: no way std::string will work. As I remarked to tenfour, I was wondering if there was a way to use std::string in way that would work. There are many tricks that I certainly am not aware of. – Vector Nov 25 '14 at 11:17
  • Thx. Pity indeed since we have some global const objects with empty strings. It is actual the destructor (with a 'free' call?) which prevents the constexpr to be kicked in. – gast128 Nov 16 '18 at 10:35
  • `const std::string constString = "constString";`, I made it by using `const` instead of `constexpr`. And I define `const` variable in a namespace. – kgbook Nov 16 '18 at 13:01

4 Answers4

206

As of C++20, yes.

As of C++17, you can use string_view:

constexpr std::string_view sv = "hello, world";

A string_view is a string-like object that acts as an immutable, non-owning reference to any sequence of char objects.

Joseph Thomson
  • 7,955
  • 1
  • 24
  • 34
  • 11
    Be aware that whenever you pass this constant to a function taking a `const std::string&` a new std::string has to be constructed. That is usually the opposite of what one had in mind when creating a constant. Therefore, I tend to say that this is not a good idea. At least you have to be careful. – Rambo Ramon Apr 04 '18 at 10:17
  • 37
    @RamboRamon `string_view` is not implicitly convertible to `string`, so there is little danger of accidentally constructing a `string` from a `string_view`. Conversely, `char const*` _is_ implicitly convertible to `string`, so using `string_view` is actually safer in this sense. – Joseph Thomson Apr 04 '18 at 13:08
  • 7
    Thanks for the clarification. I totally agree and indeed forgot that `string_view` is not implicitly convertible to `string`. IMO the problem I brought up is still valid but does not apply to `string_view` specifically. In fact, as you mentioned, it is even safer in that regard. – Rambo Ramon Apr 04 '18 at 16:25
  • 6
    It would be great if this answer said more about what `string_view` is, instead of just a link. – eric Apr 25 '18 at 13:47
  • Note that while a `std::string` has a `.c_str()` method, which returns a `char*` which is `NULL` terminated, `string_view` does *not*. Like `std::string`, it has a `.data()` method which returns a `char*` which is *not* guaranteed to be null terminated (and won't be the the `string_view` is a view into another string which has no internal `NULL`s). If you are initializing it from a compile-time constant `char` array, it *will* be `NULL` terminated, but be careful accepting `string_view` if you need to work with system calls. – Perkins Feb 24 '21 at 21:58
197

No, and your compiler already gave you a comprehensive explanation.

But you could do this:

constexpr char constString[] = "constString";

At runtime, this can be used to construct a std::string when needed.

火乔治
  • 19,950
  • 3
  • 44
  • 60
tenfour
  • 33,679
  • 12
  • 73
  • 135
  • 95
    Why not `constexpr auto constString = "constString";`? No need to use that ugly array syntax ;-) – stefan Nov 25 '14 at 10:19
  • 104
    In the context of this question, it's clearer. My point is about which string types you can choose from. `char[]` is more verbose / clear than `auto` when I'm trying to emphasize the data type to use. – tenfour Nov 25 '14 at 11:07
  • @stefan - Certainly it evaluates to what tenfour explained, but that's a very cool way to do it. :) – Vector Nov 25 '14 at 11:23
  • 11
    @tenfour Right, that's a good point. I guess I'm sometimes a bit too focused on using `auto` ;-) – stefan Nov 25 '14 at 12:15
  • I tried 'constexpr auto' in an 'template constexpr' but had to change -std from c++11 to c++1y when clang said 'warning: variable declaration in a constexpr function is a C++14 extension'. – kometen Jan 05 '16 at 10:41
  • @kometen: Do you need to go as far as `std=c++1y`? Why not just do `std=c++14`? (Since as clang says, it's a C++14 feature) – Anthony Hall Mar 31 '16 at 23:12
  • @squidbidness That would work too I guess. This is on xcode – kometen Apr 01 '16 at 05:58
  • Would it be possible to use a `string` literal: `constexpr auto s = "c"s;`? – Felix Dombek Mar 27 '17 at 17:00
  • 1
    @FelixDombek no, but with c++17 you could use `constexpr auto s = "c"sv;` due to the introduction of `string_view` – wich May 11 '17 at 13:55
  • 9
    Does it make sense to constexpr a char array in that context? If you use it to construct a string, it's going to be copied anyway. What's the difference between passing literal to the string's constructor and passing such a constexpr array to it? – KjMag Jul 21 '17 at 22:31
  • Runtime construction of `std::string` this way requires memory allocation and copying, so use with care in performance-sensitive code. – Bob Carpenter Nov 02 '17 at 19:40
  • @KjMag I'd just like to add that since the size of a `char[]` is known at compile time, (i.e. baked into the type for all intents and purposes), you can use some cool (and admittedly over-engineered) operations on it. I've had to write code that builds strings at compile time and verifies that character at index size is `'\0'`, before performing `&(*(char_array))` to decay back to regular char pointer, otherwise the code won't compile. The `char[]` is always created from a parameter pack of `char... c`, but not necessarily a string literal, which makes for an actual valid use case. – jfh Jan 17 '19 at 22:54
  • @stefan Because the outcome of using `auto` here is: (a) the code is less clear, (b) the code is less maintainable, (c) nothing else. AAA is evil! – Lightness Races in Orbit Jan 24 '19 at 23:26
  • 5
    @stefan usually I prefer `auto`. But there's a subtle difference: `auto` will be deduced as `const char* const`, hence `sizeof(constString)` will yield `8`. However, with the `char constString[]`-syntax, `sizeof(constString)` yields the number of characters in the string literal, which is presumably what one expects. – pasbi Jan 31 '19 at 16:36
  • 2
    `std::string_view` should be preferred over char array so as to avoid implicit conversion to `std::string`. In case you already have a requirement to pass it as a `std::string` then it could be better to define it as a `const std::string` or `static const std::string` – Mandeep Singh Jun 28 '19 at 11:11
31

C++20 will add constexpr strings and vectors

The following proposal has been accepted apparently: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0980r0.pdf and it adds constructors such as:

// 20.3.2.2, construct/copy/destroy
constexpr
basic_string() noexcept(noexcept(Allocator())) : basic_string(Allocator()) { }
constexpr
explicit basic_string(const Allocator& a) noexcept;
constexpr
basic_string(const basic_string& str);
constexpr
basic_string(basic_string&& str) noexcept;

in addition to constexpr versions of all / most methods.

There is no support as of GCC 9.1.0, the following fails to compile:

#include <string>

int main() {
    constexpr std::string s("abc");
}

with:

g++-9 -std=c++2a main.cpp

with error:

error: the type ‘const string’ {aka ‘const std::__cxx11::basic_string<char>’} of ‘constexpr’ variable ‘s’ is not literal

std::vector discussed at: Cannot create constexpr std::vector

Tested in Ubuntu 19.04.

21

Since the problem is the non-trivial destructor so if the destructor is removed from the std::string, it's possible to define a constexpr instance of that type. Like this

struct constexpr_str {
    char const* str;
    std::size_t size;

    // can only construct from a char[] literal
    template <std::size_t N>
    constexpr constexpr_str(char const (&s)[N])
        : str(s)
        , size(N - 1) // not count the trailing nul
    {}
};

int main()
{
    constexpr constexpr_str s("constString");

    // its .size is a constexpr
    std::array<int, s.size> a;
    return 0;
}
neuront
  • 8,164
  • 4
  • 37
  • 65
  • 26
    This is basically what c++17 `string_view` is, except that `string_view` gives you most of the functionality that you know from `std::string` – wich May 11 '17 at 13:54