1

What does char [5] const & mean?

Constant lvalue reference to array of 5 char
Or lvalue reference to array of 5 constant char
Or lvalue reference to const array of 5 char?

I am reading C++ programming language book and I am learning about pointer to char. I found this code: char s[] = "Gorm";, which reminds me that string literal is converted implicitly to const char *.

So, I felt confused that LHS and RHS are not of same type.

I used online compiler and code from here to get idea about how compiler see type of LHS and RHS. Then, I found that LHS is seen as char[5] while RHS is seen as char[5] const &.

I can interpret LHS but, I cannot understand what is "constant lvalue reference to array of 5 char" or even after implicit conversion of LHS char s[] to char* s, what is "constant lvalue reference to non const pointer to non const char"?

Is not lvalue reference by definition constant "it refers only to value initializing it"? So, why do we need const before &?

And then, how can LHS and RHS of different types be assigned?

Following is the code, I used to get type of LHS and RHS:

#include < type_traits > 
#include < typeinfo > 
#ifndef _MSC_VER
    #include < cxxabi.h > 
#endif
#include < memory > 
#include < string > 
#include < cstdlib > 
#include < iostream > // std::cout

template < class T > std::string
type_name() {
    typedef typename std::remove_reference < T >:: typeTR;
    std::unique_ptr < char, void( *)(void *) > own(#ifndef _MSC_VER abi::__cxa_demangle(typeid(TR).name(), nullptr, nullptr, nullptr), #else nullptr, #endif std::free);
    std::string r = own != nullptr
        ? own.get()
        : typeid(TR).name();
    if (std::is_const < TR >:: value) 
        r += " const";

    if (std::is_volatile < TR >:: value) 
        r += " volatile";

    if (std::is_lvalue_reference < T >:: value) 
        r += "&";
     else if (std::is_rvalue_reference < T >:: value) 
        r += "&&";

    return r;
}

int & foo_lref();
int && foo_rref();
int foo_value();
int main() {
    int i = 0;
    const int ci = 0;
    char s[] = "Gorm";
    std::cout << "decltype(s) is " << type_name < decltype("Gorm") > () << '\n';
    std::cout << "decltype(i) is " << type_name < decltype(i) > () << '\n';
    std::cout << "decltype((i)) is " << type_name < decltype((i)) > () << '\n';
    std::cout << "decltype(ci) is " << type_name < decltype(ci) > () << '\n';
    std::cout << "decltype((ci)) is " << type_name < decltype((ci)) > () << '\n';
    std::cout << "decltype(static_cast<int&>(i)) is " << type_name < decltype(static_cast < int &> (i)) > () << '\n';
    std::cout << "decltype(static_cast<int&&>(i)) is " << type_name < decltype(static_cast < int &&> (i)) > () << '\n';
    std::cout << "decltype(static_cast<int>(i)) is " << type_name < decltype(static_cast < int > (i)) > () << '\n';
    std::cout << "decltype(foo_lref()) is " << type_name < decltype(foo_lref()) > () << '\n';
    std::cout << "decltype(foo_rref()) is " << type_name < decltype(foo_rref()) > () << '\n';
    std::cout << "decltype(foo_value()) is " << type_name < decltype(foo_value()) > () << '\n';
}
  • 3
    Please don’t intentionally break the automated text formatting by putting spaces at the end of lines, it makes the text much harder to read. The automatic formatting is applied for a reason. – Konrad Rudolph Oct 09 '19 at 10:09
  • Your link is broken. Please post the entire code in the question itself. – Bartek Banachewicz Oct 09 '19 at 10:12
  • ok i just tried to make the text more clear :) – code_for_ever Oct 09 '19 at 10:12
  • not sure if I understnad the question (imho it is too many question into one). I think part of your confusing is from a misunderstanding of `const`. There is nothing wrong about `const int x = 4; int y = x;` – 463035818_is_not_an_ai Oct 09 '19 at 10:12
  • @formerlyknownas_463035818 i am confused about usage of const before &>>>i interpret this as constant lvalue reference...by definition references must be constant and can not be changed after initialization – code_for_ever Oct 09 '19 at 10:18
  • ok, then thats a different misunderstanding ;). refreces cannot be rebound to reference something else, but they are not always `const` – 463035818_is_not_an_ai Oct 09 '19 at 10:20
  • @formerlyknownas_463035818 could you explain to me how references can not be always constant or give me resource address to read about non const references? – code_for_ever Oct 09 '19 at 10:23
  • @code_for_ever This maybe help you: https://godbolt.org/z/tkPcm4 – Amadeus Oct 09 '19 at 10:24
  • @BartekBanachewicz i have answer which say that char [5] const & is not valid type from HolyBlackCat. .... you and sweenish say it is valid .....You and HolyBlackcat are of high reputation......i think my confusion about type of string literal initializing char array is not only mine.... – code_for_ever Oct 10 '19 at 08:07
  • @HolyBlackCat your answer which say that char [5] const & is not valid type .... Bartek and sweenish say it is valid .....You and Bartek are of high reputation......i think my confusion about type of string literal initializing char array is not only mine.... – code_for_ever Oct 10 '19 at 08:08
  • @code_for_ever It's just a matter of syntax; [it's possible to create a reference to an array](http://coliru.stacked-crooked.com/a/ce6af09e96b2d256), just a bit cumbersome. – Bartek Banachewicz Oct 10 '19 at 13:23

3 Answers3

3

but i can not understand what is "constant lvalue reference to array of 5 char"

This is a misnomer; it's a reference to a constant array, not a constant reference to an array. As you've observed, references can't be changed, and const can't apply to them (because they're not objects).

and then how can lhs and rhs of different types be assigned?

You can create a reference to a const object from a value of non-const object. This makes sense, because you're turning a "view" that is read and write and constraining it into "read-only."

Bartek Banachewicz
  • 38,596
  • 7
  • 91
  • 135
  • yes if i am passing argument to function , i can pass non const object but make it the argument const in function scope,,,my confusion is about how can char array "type is non constant array of non constant char" be initialized "= is initializing not assigning as arrays can not be assigned" by other object of different type "string literal is decaying to * const char ..but i really did not know what is type of string literal before decaying to pointer till i used this code ...then i was confused to find that string literal type is different from char[] type .....different regarding const & – code_for_ever Oct 09 '19 at 10:31
  • @code_for_ever those questions are more about arrays and their peculiarities, so I think this might need a different question (or simply might be answered elsewhere). In general, if you use `std::array` instead, you can pretty much stop thinking about that entirely and treat it as any other object. – Bartek Banachewicz Oct 09 '19 at 13:51
  • i know that using std::array will keep me away from low level mechanism of array ...but string literal and array represent important example to start to really understand how references and pointers work ...so i can not skip this point till i can see how string literal is typed and how it is transformed to char array – code_for_ever Oct 10 '19 at 08:13
3

char [5] const & is not a valid type. If the code you posted gives you this output, the code is broken.

Here's how you can check if a type is valid:

using type = char [5] const &; // error: expected ';' before 'const'

The actual type of string literals is const char [N], but in this case it doesn't matter.

C++ has a special rule that allows initializing character arrays with string literals. That's all.


Note that if you apply decltype to a string literal, it will give you const char (&)[N] (reference to a constant array of char). But it's not the actual type of the literal.

It might sound confusing, but expressions never have reference types. Variables do, but not expressions. See: What expressions yield a reference type when decltype is applied to them?

If decltype (when applied to an expression, rather than a variable) gives you an lvalue-reference type, it's an indication that the expression is an lvalue. (a rvalue-reference indicate an xvalue, and a lack of reference indicates a prvalue).

HolyBlackCat
  • 78,603
  • 9
  • 131
  • 207
  • references and expression categories are my worst nightmare.....they always appear to me wherever i hit wall during c++ studying......they really make headache ...real headache i swear – code_for_ever Oct 10 '19 at 11:18
2

To eliminate confusion with "weird" types, it's important to know how to read them. The clockwise/spiral method is one way to go here. Another effective method is the right/left sweep method. While these rules work best when there's a named type, it can still be adapted by simply reading right to left.

So, char[5] const & is a[n l-value] reference to a constant array of size 5 of characters. And that sounds like an accurate description of a string literal. In saying that the array is constant, it just means that the contents can't change, which is true of a string literal.

As another example, consider an array: int arr[5]. You are allowed to change the contents of the array, but arr must always point to the first element, meaning that pointer cannot change. Declaring a pointer that will always point to the same thing is accomplished with: int * const ptr;. I can change the value of what I'm pointing at, but I cannot change where I point at. If I declare it const int * const ptr or int const * const ptr, I can not change the value of what I'm pointing at, nor can I change where I point.

sweenish
  • 4,793
  • 3
  • 12
  • 23
  • you say that this is valid type for string literal ....ok any reference is initialized with known variable ....so what is the variable which initialized the string literal in first place???? i mean this `const &` was initialized by what variable????if there is no initializing variable then it was initialized by rvalue ...right???i am discussing my ideas with you.... – code_for_ever Oct 10 '19 at 08:17
  • I did, but another answer clearly shows that the value you're asking about is not valid. Instead of a homespun type printing function, just use `` – sweenish Oct 10 '19 at 14:21