C++ char*[] to char** conversion

c++, type-conversion

Solution

Jefffrey's comment references the standard, here it is:

4.2 Array-to-pointer conversion [conv.array]

An lvalue or rvalue of type “array of N T” or “array of unknown bound of T” can be converted to a prvalue of type “pointer to T”. The result is a pointer to the first element of the array.

And a prvalue is:

A prvalue ("pure" rvalue) is an expression that identifies a temporary object (or a subobject thereof) or is a value not associated with any object.

You cannot bind a non-const reference to a temporary.

int& i = int(); // error

char* argv[] = { "", "", nullptr };
// the result of the conversion is a prvalue
char**& test = argv; // error

Therefore the following code will happily compile:

#include <iostream>

void f(int& argc, char** const& argv){
    std::cout << argv[0] << std::endl; // a
}

int main()
{
    int argc = 2;
    char* argv[] = { "a", "b", nullptr };
    f(argc, argv); 
    return 0;
}

One important thing I glazed over is pointed out in Kanze's comment.

In the first example provided in the OP, `char* argv[]` and `char** argv` are equivalent. Therefore, there is no conversion.

std::cout << std::is_array<decltype(argv)>::value << std::endl; // false
std::cout << std::is_array<char**>::value << std::endl; // false
std::cout << std::is_array<char*[]>::value << std::endl; // true
std::cout << std::is_same<decltype(argv), char**>::value << std::endl; // true
std::cout << std::is_same<decltype(argv), char*[]>::value << std::endl; // false

Problem

I have this simple code that compiles without errors/warnings: ``` void f(int&, char**&){} int main(int argc, char* argv[]) { f(argc, argv); return 0; } ``` And next similar code that doesn't compile: ``` void f(int&, char**&){} int main() { int argc = 2; char* argv[] = { "", "", nullptr }; f(argc, argv); //@VS2013 error: cannot convert argument 2 from 'char *[3]' to 'char **&' //@GCC error: invalid initialization of non-const reference of type 'char**&' from an rvalue of type 'char**' return 0; } ``` Why `char*[]` can be converted to `char**&` in the first sample and can't be converted in the second sample? Does it matter if the size is known at compile time? EDIT: I think there are 2 conversions needed in the second case, and only one implicit conversion can be done by compiler. This code compiles fine: ``` void f(int&, char**&){} int main() { int argc = 2; char* temp[] = { "", "", nullptr }; char** argv = temp; f(argc, argv); return 0; } ```

Original source