37

I'm getting unexpected results from all compilers on which I tried the following (GCC 4.7.2, GCC 4.8.0 beta, ICC 13.0.1, Clang 3.2, VC10):

#include <type_traits>

int main()
{
    // This will fire
    static_assert(
        std::is_same<decltype("Hello"), char const[6]>::value, 
        "Error!"
        );
}

I would have expected the compile-time assertion above not to fire, but it does. After all, this one does not (as expected):

#include <type_traits>

int main()
{
    char const hello[6] = "Hello";

    // This will not fire
    static_assert(
        std::is_same<decltype(hello), char const[6]>::value, 
        "Error!"
        );
}

So what is the result of decltype("Hello") according to the C++11 Standard (references are highly appreciated)? What should I compare it to so that the compile-time assertion above doesn't fire?

Andy Prowl
  • 124,023
  • 23
  • 387
  • 451

1 Answers1

30

[Note: Originally, this was not meant to be a self-answered question; I just happened to find the answer myself while I was describing my attempts to investigate, and I thought it would have been nice to share it.]

According to Annex C (2.14.5) of the C++11 Standard:

The type of a string literal is changed from “array of char” to “array of const char.” [....]

Moreover, Paragraph 7.1.6.2/4 specifies (about the result of decltype):

The type denoted by decltype(e) is defined as follows:

— if e is an unparenthesized id-expression or an unparenthesized class member access (5.2.5), decltype(e) is the type of the entity named by e. If there is no such entity, or if e names a set of overloaded functions, the program is ill-formed;

— otherwise, if e is an xvalue, decltype(e) is T&&, where T is the type of e;

otherwise, if e is an lvalue, decltype(e) is T&, where T is the type of e;

— otherwise, decltype(e) is the type of e.

Since string literals are lvalues, according to the above Paragraph and the Paragraph from Annex C, the result of decltype("Hello") is an lvalue reference to an array of size 6 of constant narrow characters:

#include <type_traits>

int main()
{
    // This will NOT fire
    static_assert(
        std::is_same<decltype("Hello"), char const (&)[6]>::value, 
        "Error!"
        );
}

Finally, even though the hello variable is also an lvalue, the second compile-time assertion from the question's text does not fire, because hello is an unparenthesized id-expression, which makes it fall into the first item of the above list from Paragraph 7.1.6.2/4. Therefore, the result of decltype(hello) is the type of the entity named by hello, which is char const[6].

Community
  • 1
  • 1
Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
  • These rules make sense when you think about writing `decltype(expr) &&`. – Kerrek SB Feb 24 '13 at 00:19
  • 1
    @KerrekSB: Yes. I just found it surprising because I am kind of used to think in the gross terms of "a string literal has type `const char[]`, `decltype(x)` returns the type of `x`, so `decltype("hello")` should return `const char[6]`", forgetting the details. Lesson learnt (hopefully) – Andy Prowl Feb 24 '13 at 00:24
  • 3
    +1 both to the question and to the answer. I promise I never touch a C++ compiler anymore. –  Feb 24 '13 at 00:28
  • @AndyProwl You said you got different results with the various compilers you listed; it would be great if you could provide what the compilers you tested did. – Valloric Feb 25 '13 at 03:45
  • 2
    @Valloric: The results I get from all compilers are the same, and they are *correct*: the assertion fires. I was just having the wrong expectation, since I was expecting the assert not to fire. That's what I meant by "unexpected results". The answer should clear it up. – Andy Prowl Feb 25 '13 at 14:11