23

Can C-Strings or std::strings be created as constexpr or must they be created at run-time?

With gcc 4.9.2 I can do this:

constexpr const char foo[] = "blee"; 

(Sadly the November 2013 Customer Technology Preview does not allow Visual Studio to support this: https://stackoverflow.com/a/29255013/2642059)

But even with gcc 4.9.2 I cannot do this:

constexpr const std::string foo = "blee"; 

I get the error:

error: the type 'const string {aka const std::basic_string<char>}' of constexpr variable 'foo' is not literal constexpr const std::string foo = "blee"; ^ note: 'std::basic_string<char>' is not literal because: class basic_string ^ note: 'std::basic_string<char>' has a non-trivial destructor 

But I would like more clarification on why a std::string is not a literal. That is to say: Why must a string be constructed at run-time?

As pointed out this question can partially be answered by this: Is it possible to use std::string in a constexpr? but it does not touch on the why std::string can not be a literal which is core to the question.

17
  • 2
    I think the reason is given in the other answer: because ‘std::basic_string’ has a non-trivial destructor. Commented Mar 25, 2015 at 12:19
  • 1
    The two concepts are unrelated. You're essentially asking if std::string is a literal type. It isn't. Commented Mar 25, 2015 at 12:23
  • 1
    You also left out an important part of the error message: "... 'std::basic_string<char>' is not literal because: ... 'std::basic_string<char>' has a non-trivial destructor" which makes this a duplicate of the other question. Commented Mar 25, 2015 at 12:27
  • 1
    The obvious answer is that it requires to call operator new which doesn't really make sense as a compile-time action. The heap probably isn't even constructed yet, etc. Commented Mar 25, 2015 at 14:12
  • 1
    Is there a rationale for this question? It seems like an XY problem. Commented Mar 25, 2015 at 14:14

2 Answers 2

28

There is a proposal for a constexpr string: Compile-Time String: std::string_literal and it says:

The purpose of std::string_literal, like std::string, is to provide a convenience utility for working with text. Unlike std::string, an instantiation of std::string_literal is a literal type and so can be used at compile­time. That is, it may be the type of an constexpr object, and it may be the type of a parameter, return value or local variable of a constexpr function

which also confirms that indeed std::string is not a literal type.

So why not just make std::string a literal type?

We get a hint why from the proposal above why this not possible:

This would require a massive core language change to make something like dynamic memory available at compile­-time, or to make something like VLA/ARB and permit them in literal types. Given the violently negative reaction of Rapperswil Evolution to not only N4025 (Classes of Runtime Size), but anything that vaguely resembles VLA/ARBs, we can expect this not to happen any time soon, so this idea is a non­starter.

std::string requires dynamic memory which is not available at compile time.

Why constexpr can not be applied to std::string but can to array of char

constexpr applied to an object shall be applied to a literal type which does not apply to std::string but applies to an array of const char. From the draft C++11 standard section 7.1.5 [dcl.constexpr] (emphasis mine going forward):

A constexpr specifier used in an object declaration declares the object as const. Such an object shall have literal type and shall be initialized. If it is initialized by a constructor call, that call shall be a constant expression (5.19). […]

and from section 3.9 [basic.types]:

A type is a literal type if it is:

and includes:

  • a scalar type; or
  • an array of literal type

Arithmetic types are scalar types and include char, which covers the array of const char

and for classes:

a class type (Clause 9) that has all of the following properties:

  • it has a trivial destructor,
  • every constructor call and full-expression in the brace-or-equal-initializers for non-static data members (if any) is a constant expression (5.19),
  • it is an aggregate type (8.5.1) or has at least one constexpr constructor or constructor template that is not a copy or move constructor, and
  • all of its non-static data members and base classes are of literal types.

std::string does not meet that criteria.

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

5 Comments

@downvoter please explain, any technical mistakes, did I miss a point?
@downvoter I too would like to see this downvote removed, as I feel this expertly answers the question that I'm asking. If there is a reason for the downvote, I'd certainly like to see a comment explaining why.
I was often wondering whether it would be possible to overload std::string's constructor in a way such that for cases where it is called with a string literal (or other applicable constant expression) short enough to enable SSO, a constexpr version would jump in.
@5gon12eder sounds horrible, code shouldn't break depending on a standard library optimization
@MattMcNabb If this were implemented, it would mean of course that the standard would have to set out rules for SSO. Whether or not this would be a good idea is open to debate but I think it is an interesting thing to think about.
5

You can't use constexpr, because std::string does not have a trivial destructor. Check the requirements on cppreference.

1 Comment

Are you saying that is the sole reason std::string is not a literal type, there are several criteria for a class.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.