2016-07-22 6 views
16

質問:は暗黙のブール変換が常にvoid*に暗黙的な変換を試みるにフォールバックしていますか? (そのような変換関数が型に存在する場合)。もしそうなら、なぜですか?C++では、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()に電話できない場合、私はどのポインタにも変換しようとします。えっ、

+0

"任意のポインタへの変換を試みます" - "' void'ポインタではありません任意の "ポインタ。 'void'ポインタは' void'ポインタです。どのような種類のアドレスでも受け付けます。 – xinaiz

+1

@BlackMoses私は、受け入れられた答えを考えると実際にそうであるように見えるポインタ型を意味しました。 – jensa

+0

@JesperJuhlそれは愚かな質問ではありません。これは、コンパイラがこれを行うことが許されているかどうかと、その背後にある推論について尋ねています。あなたにとってはかなりわかりやすいかもしれませんが、初心者から中級の開発者にとっては、これは混乱する可能性があります。ポインタだけでなく、 –

答えて

15

コンパイラがユーザ定義型をboolに直接変換できない場合、コンパイラは間接的に変換を試みます。すなわち、ユーザ定義の変換を使用せずにboolに変換できる型に変換します。定義された変換。そのようなタイプのリストを含む(およびこれらに限定されているように見える)は、以下のタイプ:

  • 整数算術型(charintなど)
  • 浮動小数点演算の種類(floatdoublelong double
  • ポインタ型(void*ここに属し、それは同様にconst std::vector<Something>*であってもよい)
  • (メンバ関数へのポインタを含む)関数へのポインタ上記

注のいずれかに

  • 参照タイプが唯一のそのような間接的な変換が存在しなければならないこと。上記のリストから2つ以上の変換が可能な場合、コンパイラはあいまいさに直面し、エラーを報告します。標準のいくつかの参考文献について

  • 0

    これはブールコンテキストで使用することができる任意のタイプであってもよく、void *は、ここでは特別なものではありませんか?

    2

    任意の整数変換operatorは同じように動作します。オペレータに0を返すので、Falseです。

    論理式では整数型を使用できます。本当に何が起こっている

    4

    は、あなたのクラスは、この場合はポインタ型void*への暗黙的な変換を持っているということです。 0を返します。これはNULLマクロで、ポインタ型として受け入れられます。

    ポインタはブール値に暗黙的に変換され、NULLポインタはfalseに変換されます。

    本当にあなたがFooためのポインタするために、異なる暗黙的な変換可能性があり:

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

    をそして、あなたの出力は、あなたが両方を持っている場合、その後、あなたが得る、しかし

    operator int* const
    True

    に変更されますコンパイラエラー:

    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; 
        } 
    }; 
    
    それはコンパイラが適切なメンバ関数を選択する方法ミラーので、

    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 
    

    implicit conversionsのトピックは実際には非常に興味深い:10

    main.cpp:26:9: error: conversion from 'Foo' to 'bool' is ambiguous

    場合は、しかし、あなたは明示的にあまりにもブール、それは曖昧ではありませんが、変換を定義します与えられた議論(価値の転換、積極的な昇進など)のために。

    つまり、コンパイラには、何を意味するのかを判断しようとする際に優先順位を付けたリストがあります。 2つのオーバーロードの優先度が同じ場合、エラーが発生します。

    例えば、operator boolは常に選択されますが、あなたが代わりにoperator intoperator void*から選択しなければならなかった場合には、ポインタの変換を超える数値変換を選択しますので、その後、operator intが選択されるであろう。

    しかし、operator intoperator charの両方があった場合は、両方とも数値積分型の変換であるため、エラーが発生します。

    +0

    'operator int()'も動作します。 – xinaiz

    +0

    ありがとう、良い答え。しかし、実際にC++が「フォールバック」してオブジェクトをどのポインタ型に変換しようとするのか、私の質問には本当に答えません。 – jensa

    +0

    @jensa:より完全な説明については、私の編集を参照してください。 – AndyG

    6

    • §6.4.0.4[stmt.select]

      The value of a condition that is an expression is the value of the expression, contextually converted to bool for statements other than switch

    • §4.0.4[CONV]

      Certain language constructs require that an expression be converted to a Boolean value. An expression e appearing in such a context is said to be contextually converted to bool and is well-formed if and only if the declaration bool t(e); is well-formed, for some invented temporary variable t .

    • §8.5.17[dcl.init]

      The semantics of initializers are as follows. The destination type is the type of the object or reference being initialized and the source type is the type of the initializer expression.

    • §8.5.17.7[dcl.init]

      Otherwise, if the source type is a (possibly cv-qualified) class type, conversion functions are considered. The applicable conversion functions are enumerated (13.3.1.5), and the best one is chosen through overload resolution (13.3). The user-defined conversion so selected is called to convert the initializer expression into the object being initialized. If the conversion cannot be done or is ambiguous, the initialization is ill-formed.

    • §13.3.1.5[over.match.conv]

      Assuming that “cv1 T is the type of the object being initialized, and “cv S is the type of the initializer expression, with S a class type, the candidate functions are selected as follows:

      The conversion functions of S and its base classes are considered. Those non-explicit conversion functions that are not hidden within S and yield type T or a type that can be converted to type T via a standard conversion sequence (13.3.3.1.1) are candidate functions. For direct-initialization, those explicit conversion functions that are not hidden within S and yield type T or a type that can be converted to type T with a qualification conversion (4.4) are also candidate functions.

    • §4.13.1[conv.bool]

      A prvalue of arithmetic, unscoped enumeration, pointer, or pointer to member type can be converted to a prvalue 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 .

    関連する問題