C++ char*[]到char**的转换

Mir*_*pas 15 c++ type-conversion

我有这个简单的代码编译没有错误/警告:

void f(int&, char**&){}

int main(int argc, char* argv[])
{
    f(argc, argv);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

而下一个不编译的类似代码:

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;
}
Run Code Online (Sandbox Code Playgroud)

为什么char*[]可以转换为char**&第一个样本而不能在第二个样本中转换?如果在编译时知道大小是否重要?

编辑:我认为第二种情况需要2次转换,编译器只能进行一次隐式转换.

这段代码很好编译:

void f(int&, char**&){}

int main()
{
    int argc = 2;
    char* temp[] = { "", "", nullptr };
    char** argv = temp;
    f(argc, argv);
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

Jam*_*nze 9

因为尽管出现了,但第二个参数main有类型char**.当用作函数参数的声明时,顶级数组被重写为指针,char *[]事实上也是如此char**.但是,这仅适用于函数参数.

A char*[](如第二种情况)可以转换为a char**,但转换结果(与任何转换一样)是一个rvalue,不能用于初始化非const引用.你为什么要参考?如果要修改指针,修改char**参数main是未定义的行为(正式地,在C中,至少 - 我没有检查C++是否在这里更自由).当然,你无法修改数组的常量地址.如果您不想修改它,为什么要使用引用?


小智 3

Jeffrey 的评论引用了该标准,如下:

\n
\n

4.2 数组到指针的转换[conv.array]

\n

NT\xe2\x80\x9d 的 \xe2\x80\x9carray 类型的左值或右值或 T\xe2\x80\x9d 未知边界的 \xe2\x80\x9carray 可以转换\n为 \xe2\ 类型的纯右值x80\x9c 指向 T\xe2\x80\x9d 的指针。结果是指向数组的\n\xef\xac\x81第一个元素的指针。

\n
\n

右值是:

\n
\n

纯右值(“纯”右值)是标识临时对象(或其子对象)的表达式,或者是不与任何对象关联的值。

\n
\n

您不能将非常量引用绑定到临时引用。

\n
int& i = int(); // error\n\nchar* argv[] = { "", "", nullptr };\n// the result of the conversion is a prvalue\nchar**& test = argv; // error\n
Run Code Online (Sandbox Code Playgroud)\n

因此,以下代码将顺利编译:

\n
#include <iostream>\n\nvoid f(int& argc, char** const& argv){\n    std::cout << argv[0] << std::endl; // a\n}\n\nint main()\n{\n    int argc = 2;\n    char* argv[] = { "a", "b", nullptr };\n    f(argc, argv); \n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n
\n

Kanze 的评论中指出了一件令我困惑的重要事情。

\n

在OP中提供的第一个示例中,char* argv[]char** argv是等效的。因此,不存在转换。

\n
std::cout << std::is_array<decltype(argv)>::value << std::endl; // false\nstd::cout << std::is_array<char**>::value << std::endl; // false\nstd::cout << std::is_array<char*[]>::value << std::endl; // true\nstd::cout << std::is_same<decltype(argv), char**>::value << std::endl; // true\nstd::cout << std::is_same<decltype(argv), char*[]>::value << std::endl; // false\n
Run Code Online (Sandbox Code Playgroud)\n