21
#include <iostream>
#include <typeinfo>

int main()
{
    const char a[] = "hello world";
    const char * p = "hello world";
    auto x = "hello world";

    if (typeid(x) == typeid(a))
        std::cout << "It's an array!\n";

    else if (typeid(x) == typeid(p))
        std::cout << "It's a pointer!\n";   // this is printed

    else
        std::cout << "It's Superman!\n";
}

Why is x deduced to be a pointer when string literals are actually arrays?

A narrow string literal has type "array of n const char" [2.14.5 String Literals [lex.string] §8]

fredoverflow
  • 256,549
  • 94
  • 388
  • 662
  • My reading of the standard, for `auto` and declared type seem to indicate it should be an array, as you expect. They clearly say it resolves like a template parameter as well, which certainly would be an array (though I just tested it an in GCC the template form of the above also reports "pointer"). – edA-qa mort-ora-y Aug 18 '12 at 07:34

3 Answers3

24

The feature auto is based on template argument deduction and template argument deduction behaves the same, specifically according to §14.8.2.1/2 (C++11 standard):

  • If P is not a reference type
    • If A is an array type, the pointer type produced by the array-to-pointer conversion is used in place of A for type deduction

If you want the type of the expression x to be an array type, just add & after auto:

auto& x = "Hello world!";

Then, the auto placeholder will be deduced to be const char[13]. This is also similar to function templates taking a reference as parameter. Just to avoid any confusion: The declared type of x will be reference-to-array.

sellibitze
  • 27,611
  • 3
  • 75
  • 95
  • 1
    Note that that means `x` here isn't an array, it's a reference to an array. The subtle difference is that after `auto& x = "a"; auto& y = "a";`, `&x == &y` *may* return true, depending on whether the two distinct string literals are merged. –  Aug 18 '12 at 08:14
  • 1
    @hvd: Right, that's why I specifically said "type of the expression x" instead of "declared type of x". But it's surely worth mentioning. Thanks. :) – sellibitze Aug 18 '12 at 08:31
  • 3
    `auto&& x = "Hello world!";` is also a possibility (and yields an lvalue reference to an array, just like `auto&` does in this instance). – Luc Danton Aug 18 '12 at 08:33
  • 2
    @LucDanton Right, I always forget that string literals are lvalues. – fredoverflow Aug 18 '12 at 08:59
6

Why is x deduced to be a pointer when string literals are actually arrays?

Because of array-to-pointer conversion.

If x is to be deduced as array, only if the following is allowed:

const char m[]          = "ABC";

const char n[sizeof(m)] = m; //error

In C++, an arrray cannot be initialized with another array (like above). In such cases, the source array decays into pointer type, and you're allowed to do this instead:

const char* n = m; //ok

The rules for type-inference with auto is same as the rules of type-deduction in function template:

template<typename T>
void f(T n);

f(m);     //T is deduced as const char*
f("ABC"); //T is deduced as const char*

auto n = m;     //n's type is inferred as const char*
auto n = "ABC"; //n's type is inferred as const char*

§7.1.6.4/6 says about auto specifier:

The type deduced for the variable d is then the deduced A determined using the rules of template argument deduction from a function call (14.8.2.1) ...

Nawaz
  • 353,942
  • 115
  • 666
  • 851
  • `x` isn't initialised with `a`. `x` is initialised with `"hello world"`, which is a valid initialiser for an array of char. –  Aug 18 '12 at 07:51
  • Sure it does. Your answer only explains why `auto x = a;` would make `x` a pointer, but that is not what's in the question. –  Aug 18 '12 at 07:52
  • Except for one difference: they're valid initialisers for arrays of char. You have `const char m[] = "ABC";` in your own answer, just as you are saying that arrays aren't valid initialisers for other arrays! –  Aug 18 '12 at 07:55
  • 1
    Your edited version appears to agree with GCC even if you add reference qualifiers: `template void f(T&&); f("abc");` T is deduced as array. Same for `auto&& x = "abc";` –  Aug 18 '12 at 08:04
  • @hvd: Added quote from the spec. – Nawaz Aug 18 '12 at 08:21
-1

If you want x to be deduced as array, you can use

decltype(auto) x = "hello world";
HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207