問題描述
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!
這篇關于為什么指向 int 的指針轉換為 void* 而指向函數的指針轉換為 bool?的文章就介紹到這了,希望我們推薦的答案對大家有所幫助,也希望大家多多支持html5模板網!