【问题标题】:Why does pointer to int convert to void* but pointer to function convert to bool?为什么指向 int 的指针转换为 void* 而指向函数的指针转换为 bool?
【发布时间】:2014-10-22 13:16:40
【问题描述】:

C++ 草案标准 (N3337) 有以下关于指针转换的内容:

4.10 指针转换

2 “pointer to cv T”类型的右值,其中T 是对象类型,可以转换为“pointer to cv”类型的右值em>void。”将“指向 cv T 的指针”转换为“指向 cv void 的指针”的结果指向类型对象的存储位置的开始T 驻留,就好像该对象是 T 类型的最派生对象 (1.8)(即,不是基类子对象)。

4.12 布尔转换

1 算术、枚举、指针或指向成员类型的指针的右值可以转换为bool 类型的右值。将零值、空指针值或空成员指针值转换为 false;任何其他值都转换为 true

基于上述,将函数指针或指向int的指针转换为void*以及bool是完全可以的。

但是,如果可以选择两者,指针应该转换为哪一个?

然后,为什么指向函数的指针会转换为bool,而指向int 的指针会转换为void*

程序:

#include <iostream>
using namespace std;

void foo(const void* ptr)
{
   std::cout << "In foo(void*)" << std::endl;
}

void foo(bool b)
{
   std::cout << "In foo(bool)" << std::endl;
}

void bar()
{
}

int main()
{
   int i = 0;
   foo(&bar);
   foo(&i);
   return 0;
}

输出,使用 g++ 4.7.3:

在 foo(bool) 在 foo(void*)

【问题讨论】:

  • 任何指向 object 的指针都可以转换为 void* 并返回。例如,函数指针可能具有完全不同的大小,因此转换不是(保证是)有效的。但是您确实希望能够检查它是否为空。 (请注意,POSIX 确实要求您可以将函数指针转换为void*/从void*)。
  • 指向指针的指针不能转换为 void* 在我看来这很愚蠢,因为它应该是指向任何东西(这是一种数据类型)的指针,而指针是一种数据类型。不过,这是一个单独的问题。
  • @CashCow 指向指针的指针可以转换为void*。
  • @CashCow,也许您的意思是转换为void **。那个是不允许的。
  • 这不是我的问题的重复。我的问题是关于 iostreams 和它提供的 operator&lt;&lt; 的重载,而不是关于隐式转换规则。

标签: c++ pointers c++11


【解决方案1】:

基于上述,将函数指针或指向int 的指针转换为void* 以及bool 是完全可以的。

引用声明指向对象的指针可以转换为cv void *。函数不是对象,这将取消转换为cv void * 的资格,只留下bool


但是,如果可以选择两者,指针应该转换为哪一个?

它应该转换为const void * 而不是bool。为什么?好吧,为从过载解决 (§13.3 [over.match]/2) 开始的旅程做好准备。当然是强调我的。

但是,一旦确定了候选函数和参数列表,最佳函数的选择在所有情况下都是相同的:

——首先,候选函数的一个子集(那些具有适当数量的参数并且满足 某些其他条件)被选择以形成一组可行的功能(13.3.2)。

- 然后选择最佳可行函数基于隐式转换序列 (13.3.3.1) 需要将每个参数与每个可行函数的相应参数匹配。

那么这些隐式转换序列呢?

让我们跳到 §13.3.3.1 [over.best.ics]/3 看看什么是隐式转换序列:

格式良好的隐式转换序列是以下形式之一:
— 标准转换序列 (13.3.3.1.1),
— 用户定义的转换序列 (13.3.3.1.2),或
— 省略号转换序列 (13.3.3.1.3)。

我们对标准转换序列感兴趣。让我们跳到标准转换序列(§13.3.3.1.1 [over.ics.scs]):

1 表 12 总结了第 4 条中定义的转换并将它们划分为四个不相交的类别:左值转换、资格调整、提升和转换。 [ 注意:这些类别在值类别、cv 限定和数据表示方面是正交的:左值转换不会改变类型的 cv 限定或数据表示;资格调整不改变类型的值类别或数据表示;并且促销和转换不会更改类型的值类别或 cv-qualification。 ——尾注]

2 [注意:如第 4 条所述,标准转换序列要么是身份转换本身(即不转换),要么由其他四个类别的一到三个转换组成。

重要的部分在 /2 中。一个标准转换序列可以是一个单一的标准转换。这些标准转换列在表 12 中,如下所示。请注意,您的指针转换和布尔转换都在其中。

从这里,我们学到了一些重要的东西:指针转换和布尔转换具有相同的等级。请记住,当我们前往对隐式转换序列进行排名时 (§13.3.3.2 [over.ics.rank])。

查看 /4,我们看到:

标准转换序列按其等级排序:完全匹配是比提升更好的转换,而提升是比转换更好的转换。除非以下规则之一适用,否则具有相同等级的两个转换序列是无法区分的:

——不将指针、指向成员的指针或 std::nullptr_t 转换为 bool 的转换是 比那个好。

我们以非常明确的陈述形式找到了答案。万岁!

【讨论】:

  • @RSahu,没问题!如果您想要一个更全面的解释,您可能会在此过程中找到一些方便的东西,我已经更详细地说明了我是如何得到那个引用的。
猜你喜欢
  • 1970-01-01
  • 2021-07-22
  • 1970-01-01
  • 2015-09-10
  • 1970-01-01
  • 2011-07-31
  • 2018-06-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多