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.

Community
  • 1
  • 1
Jonathan Mee
  • 37,899
  • 23
  • 129
  • 288
  • To whom it may concern my interest in this was piqued by the answers to [this question](http://stackoverflow.com/q/29166578/2642059). – Jonathan Mee Mar 25 '15 at 12:13
  • @juhist Ah, I don't know how I missed that when I searched. So the answer is that `std::string` is not a literal? Why is that the case? Seems like it would have been simple to make a `const std::string` a literal. – Jonathan Mee Mar 25 '15 at 12:17
  • 2
    I think the reason is given in the other answer: because ‘std::basic_string’ has a non-trivial destructor. – juhist Mar 25 '15 at 12:19
  • Note that `"blee"s` exists in C++14 which is a literal of type `std::string`, maybe this will help solve whatever problem you are trying to solve – M.M Mar 25 '15 at 12:21
  • 1
    The two concepts are unrelated. You're essentially asking if `std::string` is a literal type. It isn't. –  Mar 25 '15 at 12:23
  • @MattMcNabb `constexpr const std::string foo = "blee"s;` gives me the same error on gcc 4.9.2. As the answers state I think that the problem is that `std::string` is not a literal. Not that `"blee"` is not a `constexpr`. – Jonathan Mee Mar 25 '15 at 12:26
  • 1
    You also left out an important part of the error message: "... 'std::basic_string' is not literal because: ... 'std::basic_string' has a non-trivial destructor" which makes this a duplicate of the other question. –  Mar 25 '15 at 12:27
  • You last edit somewhat changed the question, which might be why I received a downvote since my intro does not fit quite as well with the new wording even though I fully address your question. Perhaps a rewording that maintains the original feel but flows into the final question would be helpful. – Shafik Yaghmour Mar 25 '15 at 13:35
  • @ShafikYaghmour Ugh I'm Sorry. Your answer definitely got my up vote, and I'll probably accept it after we give the question a little more exposure. Anyway, I don't want to negatively effect such a good answer, but I needed to edit the question to show the differences between this question and: http://stackoverflow.com/questions/27123306/is-it-possible-to-use-stdstring-in-a-constexpr If you feel there's a good edit to this question which will showcase the differences without yanking the rug out from under your answer, by all means edit the question! – Jonathan Mee Mar 25 '15 at 13:42
  • 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. – M.M Mar 25 '15 at 14:12
  • 1
    Is there a rationale for this question? It seems like an XY problem. – M.M Mar 25 '15 at 14:14
  • 1
    @MattMcNabb Yeah after understanding the answer to [this question](http://stackoverflow.com/q/29166578/2642059) I started wondering why I couldn't make a `constexpr const std::string`. It doesn't make sense to me that a `std::string` couldn't be created until run-time. I found I could make a `constexpr const char[]`, but not a `constexpr const std::string`, so I thought I'd ask: "Why not?" – Jonathan Mee Mar 25 '15 at 14:22
  • 1
    @MooingDuck I do not believe that these are duplicates they are asking similar but different questions, an answer to that question can not fully answer this question. But if you still feel otherwise the consensus on meta seems to be that [views, votes and better answer](http://meta.stackoverflow.com/a/281733/1708801) decides the direction of closing as a duplicate and not which one is older. – Shafik Yaghmour Mar 25 '15 at 17:42
  • 1
    I edited the question to clarify the difference between this question and the question pointed out as a duplicate. – Shafik Yaghmour Mar 25 '15 at 18:19
  • @ShafikYaghmour I agree that it's different, perhaps you could request a reopen? – Jonathan Mee Mar 26 '15 at 04:07
  • @MattMcNabb I think as edited it make more sense now, the OP wants to understand why this is not possible which is a valid question. – Shafik Yaghmour Mar 26 '15 at 06:06
  • @ShafikYaghmour Yeah, I felt a little self serving voting to reopen, but then, I'd vote to reopen this if it was someone else's question so I'm gonna cast a reopen vote. – Jonathan Mee Mar 26 '15 at 11:21

2 Answers2

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.

Shafik Yaghmour
  • 154,301
  • 39
  • 440
  • 740
  • 1
    @downvoter please explain, any technical mistakes, did I miss a point? – Shafik Yaghmour Mar 25 '15 at 13:31
  • 1
    @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. – Jonathan Mee Mar 25 '15 at 13:43
  • 1
    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 Mar 25 '15 at 14:08
  • @5gon12eder sounds horrible, code shouldn't break depending on a standard library optimization – M.M Mar 25 '15 at 14:10
  • 2
    @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. – 5gon12eder Mar 25 '15 at 14:12
5

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

XapaJIaMnu
  • 1,408
  • 3
  • 12
  • 28