12

私はこれがすでにここにあったに違いないと確信していますが、この種の問題を解決する方法についての情報はあまり見つかりませんでした(電話をかけずに):

2つのオーバーロードが与えられた場合、リテラル0の関数を使用した呼び出しは、常にunsignedintバージョンを呼び出す必要があります。

void func( unsigned int ) {
    cout << "unsigned int" << endl;
}

void func( void * ) {
    cout << "void *" << endl;
}

func( 0 ); // error: ambiguous call

これが発生する理由は理解できますが、func(0u)やfunc(static_cast(0))を常に記述したくはありません。だから私の質問は:

1)これを一般的に行うための推奨される方法はありますか?

2)次のように行うことに問題はありますか?これが機能する理由は何ですか?

void func( unsigned int ) {
    cout << "unsigned int" << endl;
}

template <typename T>
void func( T * ) {
    static_assert( std::is_same<T, void>::value, "only void pointers allowed" );
    cout << "void *" << endl;
}

func( 0 ); // calls func( unsigned int )!
4

4 に答える 4

3

2)で行っていることは機能し、おそらくそれを行うためのより良い方法です。

関数を変更したくない状況では、明示的なキャストを実行して、コンパイラーにヒントを与えることができます。

func((void *) 0);
func((unsigned int) 0);
于 2011-01-06T00:03:27.140 に答える
3

C ++ 0xからのnullポインタを確認することをお勧めします(これを参照)。これは、任意のタイプのnullポインターを表すクラスを定義します。先ほど示した例は、実際にはnullptr_t(クラス)/ nullptr(値)をC++0xに含める動機付けの例です。実際には、unsigned intバージョンが必要な場合は0を、もう一方が必要な場合はnullptrを指定することで、この呼び出しを明確にすることができます。

コンパイラがサポートするまで、このトリックを小さなユーティリティクラスに実装するだけです(または、コンパイラが次の標準のこの部分を実装する場合は、このトリックを使用します)。

于 2011-01-06T00:08:16.000 に答える
2

1)これを一般的に行うための推奨される方法はありますか?

問題は、リテラル0が、intではなく、であり、 toからtoへunsigned intの有効な変換があることです。問題を処理するための推奨される方法があるとは言えません。すでに見つけた方法とは別に、別のオーバーロードを追加することもできます。intunsigned intintvoid*

void func(int i) 
{
    assert(i >= 0);
    return func(static_cast<unsigned int>(i));
}

2)次のように行うことに問題はありますか?これが機能する理由は何ですか?

テンプレートトリックが機能するのは、オーバーロードされ、テンプレート化されたバージョンを持つ関数への呼び出しを解決するためのルールが、オーバーロードされた関数の非テンプレート化バージョンを優先するように設計されているためです。

于 2011-01-06T00:13:29.453 に答える
2

1)これを一般的に行うための推奨される方法はありますか?

はい、私はあなたが2)でしたようにそれをします。2)が機能する理由については、これ以上深い意味はないと思います。タイプintが単純に一致しないT*ため、を見つける方法がありませんT。そのため、テンプレートは無視されます。

于 2011-01-06T00:01:51.523 に答える