2016-05-13 354 views
3

我已经建立了以下小例子:转换的虚假通过为const char对象*构造

class A 
{ 
    public: 
     A(const char *s); 

    private: 
     const char *p; 
}; 

A::A(const char *s) 
    : p(s) 
{ 
} 

A foo() 
{ 
    return false; 
} 

A bar() 
{ 
    return true; 
} 

g++ (Debian 4.7.2-5) 4.7.2编译,我得到以下几点:

t.cc: In function 'A foo()': 
t.cc:17:10: warning: converting 'false' to pointer type for argument 1 of 'A::A(const char*)' [-Wconversion-null] 
t.cc: In function 'A bar()': 
t.cc:23:10: error: could not convert 'true' from 'bool' to 'A' 

据我所知,如果类A具有构造函数A(T),则可以使用一个类型T而不是类A的实例。在这种情况下,编译器在调用A(T)构造函数时将T的值/实例包装在内。

此外,只有一个直接隐式转换是允许的,即,没有链A(B(c))被插入到一个值c转换C类型的,即使构造A(B)B(C)存在。

所以,我的问题:

  1. 为什么false转换为在我的例子指针?当然,一个指针不是一个对象,但是这里仍然有两个隐式转换。什么规则正在应用?
  2. 为什么转换不适用于true?我的直觉是,false可以合理地转换为nullptr(另请参阅警告),而true没有有意义的指针值。

那么,有人能解释哪些转换规则适用/不适用于上述两个示例?

+0

您的假设是正确的。所有的零值整数对象(“bool”和“char”都属于)可以隐式转换为“nullptr”。这就是为什么'int * x = 0;'(和'int * x ='\ 0';')有效,但是'int * x = 1;'不。 –

+0

真的好问题! – Destructor

回答

5

正如公布的那样,C++ 11的规则是“整数类型的整型常量表达式prvalue,其求值为0可以转换为任何指针类型,从而产生该类型的空指针值。 (C++ 98/03有一个相似的措辞规则,具有相同的净效应)。

bool是整数类型,并且false评估为0。所以false是一个有效的空指针常量。

除了这个额外的规则,C++没有从整型到指针的隐式转换。这就是为什么true不能隐式转换为指针。

但是,C++ 14更改了空指针常量的定义,以便只有整数文字(而不是整型常量表达式)有效。 false是一个布尔文字,不是一个整数,所以在C++ 14下,代码不会编译。此外,由于该问题已被标准委员会认定为C++ 11中的缺陷,因此较新的C++ 11编译器很可能在这方面遵循C++ 14规则,并且不会将false视为空值指针常量。感谢@Destructor追踪issue status


至于为什么在这里允许两个隐式转换:规则不是“最多允许一个隐式转换”。该规则是“最多允许一个用户定义的转换。“指针转换(例如将空指针常量转换为空指针值)不会被归类为用户定义的转换。因此,您的情况下的转换序列是指针转换(boolconst char *),然后是用户定义的转换( 。const char *A

+0

对于只允许一个隐式转换的规则呢?在我的第一个例子中,它们有两个:布尔型为const char *的布尔型,以及为A型的const char *。 – Giorgio

+0

是否将'false'视为空指针常量? – Giorgio

+1

@Giorgio是的,正如答案所述。它是一个整数类型的值(与整数类型同义),其值为'0'。 – Angew

0

对于1),falsebool型的,并且它可以是promotedint隐含:

  • 类型bool可以转换为int用叔他看到false变成0true变成1

所以,false基本上被提升为NULL/0(或nullptr),其可以被分配到的指针。

对于2),§4.10指出:

空指针常数是文字(2.14.2)与零值或类型的std的prvalue :: nullptr_t的整数。可以将空指针常量转换为指针类型; [...]

只有Null pointer constant可以转换为一个指针,和一个空指针常数或者是一个可积具有值0std::nullptr_ttrue(或1)没有被指定,因此它们不能被转换为指针。

+0

对于虚假是布尔和充满恐惧 –

+0

@光我没有得到你的观点 – Rakete1111

+0

不要担心:) –

2

当使用-std=c++11,-std=c++14时,OP的程序无法编译g ++ &。

在g ++ 6.1.0上查看现场演示here。它给出以下错误

prog.cc: In function 'A foo()': 
prog.cc:17:12: error: could not convert 'false' from 'bool' to 'A' 
    return false; 
      ^~~~~ 

查看实况演示here关于铿锵声++。它给出了以下诊断。

main.cpp:17:12: error: no viable conversion from returned value of type 'bool' to function return type 'A' 
    return false; 
      ^~~~~ 
main.cpp:1:7: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'bool' to 'const A &' for 1st argument 
class A 
    ^
main.cpp:1:7: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'bool' to 'A &&' for 1st argument 
class A 
    ^
main.cpp:10:4: note: candidate constructor not viable: no known conversion from 'bool' to 'const char *' for 1st argument 
A::A(const char *s) 
^
main.cpp:22:12: error: no viable conversion from returned value of type 'bool' to function return type 'A' 
    return true; 
      ^~~~ 
main.cpp:1:7: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'bool' to 'const A &' for 1st argument 
class A 
    ^
main.cpp:1:7: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'bool' to 'A &&' for 1st argument 
class A 
    ^
main.cpp:10:4: note: candidate constructor not viable: no known conversion from 'bool' to 'const char *' for 1st argument 
A::A(const char *s) 
^
main.cpp:7:21: warning: private field 'p' is not used [-Wunused-private-field] 
     const char *p; 
        ^

不应该转换为指针类型,因为C++ 11。查看我曾经问过的类似问题here