web-dev-qa-db-ja.com

暗黙的な変換と演算子のオーバーロード

だから、私はこのようなものを書いた

#include <iostream>
using namespace std;

void f(int32_t i)
{
    cout << "int32: " << i << endl;
}

void f(int16_t i)
{
    cout << "int16: " << i << endl;
}

void f(int8_t i)
{
    cout << "int8: " << i << endl;
}

void f(uint32_t i)
{
    cout << "uint32: " << i << endl;
}

void f(uint16_t i)
{
    cout << "uint16: " << i << endl;
}


int main() {
    uint8_t i = 0u;
    f(i);
    return 0;
}

そしてそれは印刷されました

int32: 0

私は少し混乱しています:

  • これは明確に定義された動作ですか、それとも実装固有ですか?

  • ここでどのオーバーロードが使用され、変数がどの型に変換されるかを決定するルールは何ですか?

17
Eternal

さまざまなオーバーロードされた関数に必要な変換を比較する場合、 "promotion" は標準の "変換"よりも優れた変換シーケンスと見なされます。すべての算術型は、最大1つの他の型に昇格できます。 (昇格は、printfのようなCスタイルの可変個引数関数に引数を渡すときにも使用されます。単項_+_演算子は、_+n_のような算術式の昇格を強制するために使用できます。 。)

文字型またはboolではない整数型の場合、昇格された型は次のとおりです。

  • intが元の型のすべての値を表すことができる場合、int;
  • それ以外の場合、_unsigned int_が元の型のすべての値を表すことができる場合、_unsigned int_;
  • それ以外の場合、元のタイプ自体(プロモーションは何もしません)

あなたの例では、オーバーロードされた関数を比較するとき、「完全一致」が最善ですが、正確に_int8_t_(または_int8_t&_または_const int8_t&_)を取る関数はありません。 _uint8_t_の昇格された型はintです。これは、0〜255をはるかに超える範囲をサポートする必要があるためです。そして、明らかにあなたのシステムでは、_int32_t_はintのエイリアスであるため、関数void f(int32_t);は引数のプロモーションのみを必要とします。他の関数はすべて実行可能ですが、引数で整数変換が必要です。したがって、void f(int32_t);は最適なオーバーロードと見なされます。

したがって、質問に対する技術的な答えは、実装固有であるということですが、intと_<cstdint>_型の間の関係のためだけであり、過負荷解決規則のためではありません。

22
aschepler

動作は明確に定義されており、but実装固有です。 16ビットのintでは、これは異なっていたでしょう。

標準の特定のルールは次のとおりです。

[[over.best.ics] オーバーロードの解決。 [conv.prom] 統合プロモーション。

9
Kit.