2008-06-06

にわかに信じがたいC++のOverload resolutionのルール

class string {
public:

string(const char*);
} ;

void f(string, string, bool = false) ; // 1
void f(string, bool = false) ; // 2

void g()
{
  f(“Hello”, “Goodbye”) ;// 2が呼ばれる
}

なぜか。まずオーバーロードの解決をするために、一つ目の引数を見る。これはどちらの関数も、string型を取る。string型はコンストラクタにconst char *型を取るので、コンパイラはstring型に変換できる。二つ目の引数はどうか。関数1はstring型を引数に取るが、関数2はboolである。人間的に考えると、関数1を呼んで欲しい。しかし、規格では、関数2が呼ばれるのが正しい挙動だ。なぜかというと、コンストラクタを使って変換するより、ポインタをboolに変換するほうが、規格上、より高い候補になるからだ。そんなわけで、コンパイラは、関数2を、正しく、呼ぶことになる。。

via Some C++ Gotchas

3 comments:

rt said...

boolをintやshortにすると1が呼ばれますね(VC9)
イマイチよく分かりません・・・

江添亮 said...

standard conversionsには、
ポインタからboolに変換するということは規定されていますが、ポインタから整数値に変換するという規格はありません。

int * f(void) { static int x ; return &x ; }

int main()
{
bool b = f() ;
//オッケー
if ( b == true )
std::cout << "NULLじゃないよ!" << std::endl ;

//エラー、reinterpret_castが必要
unsigned int i = f() ;
if ( i == 0xdeadbeef)
std::cout << "ポインタの値は0xdeadbeef だよ!" << std::endl ;
}

江添亮 said...

もっとこの問題にあった、いい例を思いついた。

void f(bool) { }
void g(int) { }

int main()
{
int x ;
int * ptr = &x ;
f(ptr) ;//問題ない、ポインタからboolへの変換
g(ptr) ;//エラー、ポインタから整数値への変換。明示的なreinterpret_castが必要
}