鍋あり谷あり

テーマを決めずに適当に書いています。

私の知らなかったC++もっともっと

私の無知をさらけ出すシリーズ第4弾。
まずは前回の続き。ポインタに変換できる const int の話。
昨日書いた例は、今ひとつ不幸な感じがしなかったように思うので、もうちょっと不幸そうな例を書いておく:

struct x{ x(double){} };
void foo( x ){  cout << "x" << endl;  }
void foo( char * ){  cout << "char *" << endl;  }

const int zero = std::max( -1, 0 );
#define MAX( a, b ) ((a)>(b)?(a):(b))
const int ZERO = MAX( -1, 0 );

void test()
{
  foo( ZERO ); // "char *"
  foo( zero ); // "x"
}

わかりやすいように std::max と MAX という形にしたが、処理系によっては max がマクロだったりそうじゃなかったりするわけで、わかりにくくなる。
zero や ZERO の型は、両者とも const int なので、型では区別がつかない。区別するためには、template 引数に食わしてみるとか、そういう対応をするといいかもしれない:

template< int x > class compile_time_constant_tester{};
void test2()
{
  compile_time_constant_tester<ZERO>(); // OK.
  foo( ZERO ); // "char *"
  compile_time_constant_tester<zero>(); // コンパイルエラー。
  foo( zero ); // "x"
}

で。
今日の最大の発見は、void を返す return 文。

void foo(){}
void test()
{
  return foo(); // OK.
}

6、7年前、こういうソースを書いたらコンパイルエラーになったという記憶があるんだが、知らない間に合法になっていたらしい。あるいはコンパイラのバグだったのか。
びっくり。
いつの間に。

それと。だいぶ些細な発見だが、演算子の優先順位だけでは演算の優先順位が決まらないという話も、かなり驚いた:

bool foo(){  return true;  }
void test()
{
  int a=0, b=0, c=0, d=0, e=0;
  a = foo() ? b=1, c=2 : d=3, e=4; // OK.
  cout << a << ", " << b << ", " << c << ", " 
       << d << ", " << e << ", " << endl; // 2, 1, 2, 0, 4
}

三項間演算子は代入やカンマよりも優先順位が高いので、上記の a への代入はコンパイルエラーになると思っていたんが、そうではないらしい。
結果からわかるとおり、括弧をたくさん付けると
 ( a = ( foo() ? ( (b=1), (c=2) ) : ( d=3 ) ) ), (e=4) ;
となる。b=1 のあとにあるコンマは、三項間演算子よりも優先順位が高く、e=4 の前にあるコンマは、三項間演算子よりも優先順位が低いように見える。
難しい。
まあこんな式を括弧なしで書く奴はいないと思うので、問題にはならないと思う。

#写真と本文は関係ありません。