20

三項演算子には驚くべき制限があることは知っていますが、これがコンパイルに失敗することに少し戸惑いました。

void foo(bool b)
{
    int* ptr =  ((b) ? NULL : NULL);
}

明らかに、それは問題を示すために必要な最小限です。エラーは次のとおりです。

[BCC32 Error] Unit11.cpp(20): E2034 Cannot convert 'int' to 'int *'

コンパイラは100%未満のEmbarcadero C ++ Builder 2010であるため、コンパイラのバグは不可能ではありません...

注:Parensは、私の意図についての混乱を避けるために変更されました。

注2:そもそもこの構成に到達した方法について少し混乱したので、言い訳をしますa = b? c : d。b、c、dがすべて複雑な式であるなどの行でコンパイルエラーが発生していました。 。それを絞り込むために、原因が原因であるかどうかを確認するためにc、とdNULLsに置き換えましbた。この時点で、すべてが手押し車で地獄に行きました。

4

3 に答える 3

23

NULLはに展開されるマクロです(または、たとえば、0の値を持つ積分定数式)。それ以外は「特別」ではありません。0(1 - 1)

値がゼロの整数定数式は、nullポインター定数として使用できます。これが、int* ptr = 0;許可されている理由です。ただし、ここでは、式はb ? 0 : 0;です。これは積分定数式bではありません(定数ではありません)。そのタイプはint、であり、暗黙的に次のように変換することはできません。int*

回避策は、ポインタ型が必要であることを明示的に指定することです。

int* const null_int_ptr = 0;
int* ptr = b ? null_int_ptr : null_int_ptr;

ただし、この例は少し工夫されています。通常、条件演算子を使用する場合、引数の少なくとも1つは実際にはポインター型です(例b ? ptr : 0)。オペランドの1つがポインター型である場合、0は暗黙的に同じポインター型に変換されるため、条件式全体の型はポインター型であり、ではありませんint

この「問題」が発生する可能性がある唯一のケースは、条件演算子の2番目と3番目のオペランドの両方としてnullポインター定数が使用されている場合です。これは、かなり奇妙なことです。

于 2011-07-25T16:59:33.203 に答える
4

問題は、システム上で、三項演算子のコンテキストでintと見なされるNULLように定義されていることです。オペランドの1つが、もう1つを自動昇格する必要がある0場合。static_castint*

しかし、なぜそもそもそのような構成を使用しているのでしょうか?

于 2011-07-25T17:00:32.610 に答える
3

NULLint型またはでさえあると定義できるlongので、三項演算子は同じ型を持ちます。ポインタ型への暗黙の変換はないため、コンパイラはエラーを生成します。ここでの落とし穴は、ゼロに評価される定数整数式(悪名高いnullポインター定数)からの暗黙の変換があることです。

ここで考えられる解決策は、明示的なキャストです。

int* ptr =  b ? (int*) NULL : NULL;
于 2011-07-25T17:03:38.727 に答える