为什么指向 int 的指针转换为 void* 而指向函数的指针转换为 bool?
C++ 草案标准 (N3337) 有以下关于指针转换的内容:
<块引用>4.10 指针转换
2 类型为指向 cv T
的指针"的右值,其中 T
是对象类型,可以转换为输入指向 cv void
的指针".将指向 cv T
的指针"转换为指向 cv void
的指针"的结果指向T
类型的对象所在的存储位置的开始,就好像该对象是 T
类型的最派生对象 (1.8)(即,不是基类)子对象).
和
<块引用>4.12 布尔转换
1 算术、枚举、指针或指向成员类型的指针的右值可以转换为 bool
类型的右值.零值、空指针值或空成员指针值转换为假;任何其他值都转换为 true
基于上述,将函数指针或指向 int
的指针转换为 void*
以及 bool代码>.
但是,如果两者都可以选择,指针应该转换为哪一个?
然后,为什么指向函数的指针会转换为 bool
而指向 int
的指针会转换为 void*
?
程序:
#include 使用命名空间标准;void foo(const void* ptr){std::cout <<在 foo(void*)"中<<std::endl;}void foo(bool b){std::cout <<在 foo(bool)"中<<std::endl;}空栏(){}int main(){int i = 0;foo(&bar);foo(&i);返回0;}
输出,使用 g++ 4.7.3:
<前>在 foo(bool)在 foo(void*) 解决方案基于上述,将函数指针或指向
int
的指针转换为void*
以及bool代码>.
引用说明指向对象的指针可以转换为cv void *
.函数不是对象,这取消了转换为 cv void *
的资格,只留下 bool
.
但是,如果两者都可以选择,指针应该转换为哪一个?
它应该通过 bool
转换为 const void *
.为什么?好吧,准备开始重载解决方案 (§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 限定.― 尾注 ]
2 [注:如第 4 条所述,标准转换序列要么是身份转换本身(即不转换),要么由其他四个类别的一到三个转换组成.
重要的部分在/2.标准转换序列可以是单个标准转换.这些标准转换列于表 12 中,如下所示.请注意,您的指针转换和布尔转换都在其中.
从这里,我们学到了一些重要的东西:指针转换和布尔转换具有相同的等级.请记住,当我们开始对隐式转换序列进行排名时(第 13.3.3.2 节 [over.ics.rank]).
查看/4,我们看到:
<块引用>标准转换序列按其等级排序:完全匹配比促销更好的转换,而促销比转换更好.除非以下规则之一适用,否则具有相同等级的两个转换序列是不可区分的:
――不将指针、指向成员的指针或 std::nullptr_t 转换为 bool 的转换是比那个好.
我们以非常明确的声明形式找到了答案.万岁!
The C++ Draft Standard (N3337) has the following about conversion of pointers:
4.10 Pointer conversions
2 An rvalue of type "pointer to cv
T
," whereT
is an object type, can be converted to an rvalue of type "pointer to cvvoid
." The result of converting a "pointer to cvT
" to a "pointer to cvvoid
" points to the start of the storage location where the object of typeT
resides, as if the object is a most derived object (1.8) of typeT
(that is, not a base class subobject).
and
4.12 Boolean conversions
1 An rvalue of arithmetic, enumeration, pointer, or pointer to member type can be converted to an rvalue of type
bool
. A zero value, null pointer value, or null member pointer value is converted to false; any other value is converted to true
Based on the above, it is perfectly OK to convert a function pointer or a pointer to an int
to a void*
as well as bool
.
However, given the choice of both, which one should a pointer convert to?
And then, why does a pointer to a function convert to a bool
and a pointer to an int
convert to a void*
?
Program:
#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;
}
Output, using g++ 4.7.3:
In foo(bool) In foo(void*)
解决方案
Based on the above, it is perfectly OK to convert a function pointer or a pointer to an
int
to avoid*
as well asbool
.
The quotation states that a pointer to an object can be converted to cv void *
. Functions are not objects, and this disqualifies the conversion to cv void *
, leaving only bool
.
However, given the choice of both, which one should a pointer convert to?
It should convert to const void *
over bool
. Why? Well, prepare for a journey that starts in Overload Resolution (§13.3 [over.match]/2). Emphasis mine, of course.
But, once the candidate functions and argument lists have been identified, the selection of the best function is the same in all cases:
― First, a subset of the candidate functions (those that have the proper number of arguments and meet certain other conditions) is selected to form a set of viable functions (13.3.2).
― Then the best viable function is selected based on the implicit conversion sequences (13.3.3.1) needed to match each argument to the corresponding parameter of each viable function.
So what about these implicit conversion sequences?
Let's jump over to §13.3.3.1 [over.best.ics]/3 and see just what an implicit conversion sequence is:
A well-formed implicit conversion sequence is one of the following forms:
― a standard conversion sequence (13.3.3.1.1),
― a user-defined conversion sequence (13.3.3.1.2), or
― an ellipsis conversion sequence (13.3.3.1.3).
We're interested in standard conversions sequences. Let's pop over to Standard Conversion Sequences (§13.3.3.1.1 [over.ics.scs]):
1 Table 12 summarizes the conversions defined in Clause 4 and partitions them into four disjoint categories: Lvalue Transformation, Qualification Adjustment, Promotion, and Conversion. [ Note: These categories are orthogonal with respect to value category, cv-qualification, and data representation: the Lvalue Transformations do not change the cv-qualification or data representation of the type; the Qualification Adjustments do not change the value category or data representation of the type; and the Promotions and Conversions do not change the value category or cv-qualification of the type. ― end note ]
2 [ Note: As described in Clause 4, a standard conversion sequence is either the Identity conversion by itself (that is, no conversion) or consists of one to three conversions from the other four categories.
The important part is in /2. A standard conversion sequence is allowed to be a single standard conversion. These standard conversions are listed in Table 12, shown below. Notice that both your Pointer Conversions and Boolean Conversions are in there.
From here, we learn something important: Pointer conversions and boolean conversions have the same rank. Remember that as we head to Ranking Implicit Conversion Sequences (§13.3.3.2 [over.ics.rank]).
Looking at /4, we see:
Standard conversion sequences are ordered by their ranks: an Exact Match is a better conversion than a Promotion, which is a better conversion than a Conversion. Two conversion sequences with the same rank are indistinguishable unless one of the following rules applies:
― A conversion that does not convert a pointer, a pointer to member, or std::nullptr_t to bool is better than one that does.
We've found our answer in the form of a very explicit statement. Hooray!
相关文章