为什么我不能使用foo(char* args[])来执行foo({"asd", "asd1"})操作?

9

我正在阅读《C++ Primer》,在第6.2节中,书中写道:

“参数初始化的方式和变量初始化一样。”

然而,当我这样做时:

void foo(char* args[]) {return;}

int main() {

char* args[]={"asd","dsa"};  // ok.

foo({"asd","dsa"});          // error.

}

为什么会这样呢?

错误信息是什么? - tomi.lee.jones
5
书籍有时会说谎,有时是为了让事情更简单易懂,有时是因为作者自己也不太懂。 - Cory Nelson
@CoryNelson 所以说,在 C 和 C++ 中,数组有点像一个边角案例。 - Quentin
5
初始化工作的方式相同。然而,声明不同。特别地,函数参数args的类型不是一个数组。 - T.C.
@T.C. 我认为你是对的,因为你不能将数组传递给函数。它只是一个 **char。 - 4nt
@CoryNelson 这基本上是正确的:参数从它们的参数复制初始化。 OP之所以在这种情况下被绊倒,是因为参数列表中数组声明符的调整(在参数初始化之前发生)。 - M.M
4个回答

4

正如评论中@T.C.所指出的那样,函数参数中的args被转换为char **,因为函数无法将数组作为参数传递。由于你不能这样做:

char **asd={"asd","dsa"}; 

代码是非法的。我的困惑来自于这一事实。

char* args[]={"asd","dsa"};
char **asd=args;

是合法的。

1
相关阅读:https://dev59.com/amEh5IYBdhLWcg3wNxEn - M.M

3

通常可以利用新的初始化语法和语义来使用匿名数组作为参数,但需要跨越一些障碍。例如:

typedef const char *CC2[2];

void foo(const CC2 &a) {}

int main() {
  foo({ "asd", "dsa" });
}

然而,在您的情况下,该技术将无法帮助您,因为您正在请求对临时数组进行数组到指针的转换。在C++中,这是非法的。

typedef int A[2];

const A &r = A{ 1, 2 }; // reference binding is OK
int *p = A{ 1, 2 };     // ERROR: taking address is not OK

所以,如果您真的想做类似的事情,可以按照以下步骤操作。
template <size_t N> void foo(const char *const (&args)[N]) {}

int main() {
  foo({ "asd", "dsa" });
}

但这并不完全是你最初想要的。

0
"参数初始化与变量初始化的方式相同。"这是在调用构造函数方面是正确的,我认为他们的意思是。然而,初始化器是特殊的,不同于您可以分配给变量或传递给函数调用的普通值表达式。
C/C++没有一种方法来编写文字匿名数组。您只能将其作为初始化程序声明变量时执行。

0

为什么呢?

首先,在这两种情况下,你需要使用 char const*,因为你正在使用字符串字面量。

其次,如果参数类型是数组,则 {...} 可以工作,但是 char*[] 会被 调整char**(由于衰减),无法用 大括号初始化列表 进行初始化。


或者使用 std::stringstd::vector,因为你已经应该这样做了:

void foo(std::vector<std::string> args) {return;}

并且:

foo({"asd","dsa"});

会很好地工作。


你所说的 {...} 在初始化非类类型(且不是从 auto 推导)时,从未被推导为 std::initializer_list。而且,参数类型也不是 T[]。声明会被调整T*,如果参数是数组,则会隐式转换。 - David G
我正在使用Visual C++ 2010,但它不包括initializer_list。 - 4nt

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接