为什么char{}和char()可以作为char*参数的临时变量?

18

在使用Visual C++ 2017(带有/std:c++14/std:c++17选项)时,以下代码可以正常工作:

void TakePtr(char*); // const or not

int main()
{ 
     TakePtr(char{});
     TakePtr(char());
}

我不明白它为什么有效。

显然,以下方法也可以工作(如预期):

void TakeChar(char);

   TakeChar(char{});
   TakeChar(char());
当使用 char{}char() 作为参数时,编译器如何推断(或转换)类型 charchar* 呢?
现在,如果我同时拥有 charchar* 两种重载,它可以正常工作而不会出现任何关于歧义的错误/警告:
void TakePtr(char*);
void TakePtr(char);

    TakePtr(char{});  // Chooses 'char'
    TakePtr(char());  // Chooses 'char'
为什么编译器对于 TakePtr(char*) 中的 char{} 是可以接受的? 为什么它没有在选择更好的版本时给出警告/错误?这种行为必定会破坏现有的代码。
当然,编译器对以下内容并不满意:
void TakePtr(char*);

    char c{};
    TakePtr(c);

11
一个猜测:char() 构造一个临时的 (char)0,可以转换为任何可接受空指针的整数 0。我在 godbolt 上测试过,我相信我是正确的:Compiler Explorer - Scheff's Cat
@Scheff,xor ecx,ecx; call void TakePtr(char *) - Evg
@Evg 是的,这就是为什么我相信我是正确的。;-) - Scheff's Cat
1
通过添加 void TakePtr(char) = delete; 可能可以抑制不良行为。 - Eljay
1
@Scheff,干得好!TakePtr(char{8})失败了,而TakePtr(char{0})没有。 - Ajay
显示剩余3条评论
2个回答

13

因为视觉经常会产生偏差,特别是老旧的视觉系统。你的代码会提示clang报错:

<source>:9:6: error: no matching function for call to 'TakePtr'

     TakePtr(char{});

     ^~~~~~~

<source>:5:6: note: candidate function not viable: no known conversion from 'char' to 'char *' for 1st argument

void TakePtr(char*); // const or not

     ^

<source>:10:6: error: no matching function for call to 'TakePtr'

     TakePtr(char());

     ^~~~~~~

<source>:5:6: note: candidate function not viable: no known conversion from 'char' to 'char *' for 1st argument

void TakePtr(char*); // const or not

     ^

2 errors generated.

Visual在遵循C++标准方面被认为是“不稳定”的,所以不要过于依赖它。最好使用clang / gcc进行验证,以确保正确性。


3
这只是MSVC落后的问题:在C++03中规定,任何整数类型和值为0的常量表达式都是空指针常量,并且可以转换为char*。当然,char()符合条件,而char{}意味着相同的事情,尽管它从未与规则重叠。

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