簡體   English   中英

C ++,bool轉換是否總是回退到隱式轉換為void *?

[英]C++, does bool conversion always fall back to implicit conversion to void*?

問題:隱式bool轉換是否總是回退到嘗試隱式轉換為void* (如果存在類型的轉換函數)。 如果是這樣,為什么?

考慮以下簡短程序:

#include <iostream>

class Foo{
public:

    operator void*() const
    {
        std::cout << "operator void*() const" << std::endl;
        return 0;
    }
};

int main()
{
    Foo f;

    if(f)
        std::cout << "True" << std::endl;
    else
        std::cout << "False" << std::endl;

    return 0;
}

該程序的輸出是:

operator void*() const
False

意思是,調用void*的轉換函數。 如果我們在轉換函數前面標記explicit限定符,則隱式轉換為void*將失敗。

編輯:似乎很多答案是“空指針可以轉換為false ”。 我理解這一點,我的問題是關於“如果我不能直接調用operator bool()那么我將嘗試轉換為任何指針”。

如果編譯器無法直接將用戶定義的類型轉換為bool ,那么它會嘗試間接地執行此操作,即將(通過用戶定義的轉換)轉換為可以轉換為bool而不涉及其他用戶定義的轉換的類型。 這些類型的列表包括(並且似乎僅限於)以下類型:

  • 整數算術類型( charint等)
  • 浮點算術類型( floatdoublelong double
  • 一個指針類型( void*屬於這里,但它也可以是const std::vector<Something>*
  • 指向函數的指針(包括指向成員函數的指針)
  • 任何上述參考類型

但請注意,只有一個這樣的間接轉換必須存在。 如果上述列表中的兩次或多次轉換成為可能,則編譯器將面臨歧義並報告錯誤。

對於標准中的一些參考:

  • §6.4.0.4[stmt.select]

    作為表達式的條件的值是表達式的值,對於除switch語句,上下文轉換為bool

  • §4.0.4[轉]

    某些語言結構要求將表達式轉換為布爾值。 在這樣的上下文中出現的表達式e被稱為在上下文中被轉換為bool並且當且僅當聲明bool t(e);才是格式良好的bool t(e); 對於一些發明的臨時變量t

  • §8.5.17[dcl.init]

    初始化器的語義如下。 目標類型是要初始化的對象或引用的類型, 源類型是初始化表達式的類型。

  • §8.5.17.7[dcl.init]

    否則,如果源類型是(可能是cv限定的)類類型,則考慮轉換函數。 列舉了適用的轉換函數(13.3.1.5),並通過重載決策(13.3)選擇最佳函數。 調用如此選擇的用戶定義轉換以將初始化表達式轉換為正在初始化的對象。 如果轉換不能完成或不明確,則初始化是錯誤的。

  • §13.3.1.5[over.match.conv]

    假設“cv1 T是要初始化的對象的類型,並且“cv S是初始化表達式的類型,其中S是類類型,候選函數選擇如下:

    考慮S及其基類的轉換函數。 那些未隱藏在S和yield類型T非顯式轉換函數或可通過標准轉換序列(13.3.3.1.1)轉換為類型T類型是候選函數。 對於直接初始化,那些未隱藏在S和yield類型T顯式轉換函數或者可以通過限定轉換(4.4)轉換為類型T類型也是候選函數。

  • §4.13.1[conv.bool]

    算術,無范圍枚舉,指針或指向成員類型的指針的prvalue可以轉換為bool類型的prvalue。 零值,空指針值或空成員指針值轉換為false ; 任何其他值都轉換為true

真正發生的是你的類在這種情況下隱式轉換為指針類型void* 返回0 ,這是NULL宏,它被接受為指針類型。

指針隱式轉換為布爾值,空指針轉換為false。

真的,你可以對Foo指針進行不同的隱式轉換:

operator int*() const
{
    std::cout << "operator int* const" << std::endl;
    return new int(3);
}

你的輸出將變為

operator int * const
真正

但是,如果您同時擁有這兩個 ,則會出現編譯器錯誤:

class Foo{
public:

    operator int*() const
    {
        std::cout << "operator int* const" << std::endl;
        return new int(3);
    }
    operator void*() const
    {
        std::cout << "operator void*() const" << std::endl;
        return 0;
    }
};

main.cpp:26:9:錯誤:從'Foo'到'bool'的轉換是不明確的

但是,如果你明確定義了一個轉換,那么它也不是模糊的:

operator void*() const
{
    std::cout << "operator void*() const" << std::endl;
    return 0;
}

operator bool() const
{
     std::cout << "operator bool() const" << std::endl;
    return true;
} // <--- compiler chooses this one

隱式轉換的主題實際上非常有趣,因為它反映了編譯器如何為給定的參數(值轉換,整體促銷等)選擇適當的成員函數。

也就是說,編譯器有一個優先級列表,它會在嘗試確定您的意思時選擇。 如果兩個重載具有相同的優先級,則會出現錯誤。

例如,將始終選擇operator bool ,但如果您必須從operator intoperator void*進行選擇,則將選擇operator int ,因為它選擇了數字轉換而不是指針轉換。

但是,如果你有operator intoperator char ,那么你會得到一個錯誤,因為它們都是數字積分轉換。

任何積分轉換operator都以相同的方式工作。 您在運算符中返回0 ,因此為False

operator [int,double,uint64_t,<any_integral>]() const
{
    std::cout << "integral operator called" << std::endl;
    return 0;
}

任何整數類型都可以用於邏輯表達式。

這可以是任何可以在布爾上下文中使用的類型,而void *在這里並不特別,是嗎?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM