25

この問題は、 enums を使用したオーバーロードの解決に関するこの質問に答えるときに発生しました。

long long原因は間違いなく MSVC2012NovCTP のバグでしたが (標準テキストと gcc 4.7.1 でのテストによると)、次の動作が発生する理由がわかりません。

#include <iostream>

enum charEnum : char { A = 'A' };

void fct(char)      { std::cout << "fct(char)"      << std::endl; }
void fct(int)       { std::cout << "fct(int)"       << std::endl; }
void fct(long long) { std::cout << "fct(long long)" << std::endl; }

int main() 
{
    fct('A');
    fct(A);
}

MSVC2012NovCTP と gcc 4.7.1 の両方がこの出力に同意します。

fct(文字)
fct(int)

からにA変換すべきではありませんか? に変換されるのはなぜですか?charEnumcharAint

編集: clang は、呼び出しがあいまいであると不平を言います。これは、以下の私の解釈に同意します。とはいえ、それが基礎となる型であるとのみ考えられていれば、私はそれをはるかに直感的に見つけることができます.


関連する 2 つの標準の抜粋は §7.2/9 です。

列挙子の値またはスコープのない列挙型のオブジェクトは、整数昇格によって整数に変換されます (4.5)

そして§4.5/4:

基になる型が固定されている (7.2) スコープのない列挙型の prvalue は、その基になる型の prvalue に変換できます。さらに、基になる型に整数昇格を適用できる場合、基になる型が固定されている範囲指定されていない列挙型の prvalue も、昇格された基になる型の prvalue に変換できます。

したがってcharEnum、 に変換するか、などcharの の任意の整数昇格を行うことができます。charint

しかし、これは私には漠然としています。なぜなら、「できる」は実際にどちらが選択されるかを正確に示していないからです。どちらかといえば、この表現はあいまいである必要がありますchar。をコメントアウトするfct(int)と、呼び出しあいまいになります。なぜint特別なのですか?

私が考えることができる唯一のことは、統合プロモーションが再帰的に適用されるということですが、それを強制するものは何もありません。

4

2 に答える 2

9

C++03 では、ルールは次のとおりでした。

スコープのない列挙型 (7.2 [dcl.enum]) の右辺値は、列挙のすべての値 (つまり、bmin から bmax の範囲の値) を表すことができる次の型の最初の右辺値に変換できます。 7.2 [dcl.enum]): int、unsigned int、long int、unsigned long int、long long int、または unsigned long long int。

C++03 コンパイラでintは、リストの最初にあるため、 が選択されます。


C++11 では、基になる型が導入されました。したがって、685. Integral Promotions of enumeration ignores fixed 基本型、この文言は§4.5/4で引用した段落に変更され、欠陥レポートを読んだところ、委員会の意図はfct(char)(基本型)にあったようです選ばれます。

ただし、 core issue 1601での議論によると、C++11 のテキストは実際には変換をあいまいにします (fct(char)両方fct(int)とも可能であり、どちらも優先されません)。

次の修正が提案され、C++14 に受け入れられました。

基になる型が基になる型に固定されている列挙型を昇格する変換は、昇格された基になる型に昇格する変換よりも優れています (2 つが異なる場合)。

これは C++11 の欠陥として報告されているため、コンパイラは C++11 モードでこの修正を適用し、 を呼び出す必要がありますfct(char)

于 2013-01-08T05:00:27.607 に答える
4

現在の標準の私の解釈によれば、呼び出しはあいまいでなければなりません。説明に続きます。

4.5/4 あたり:

「基になる型が固定されている範囲外の列挙型の prvalue (7.2) は、その基になる型の prvalue に変換できます。さらに、基になる型に整数昇格を適用できる場合、基になる型がスコープ外の列挙型の prvalue昇格した基になる型の prvalue に変換することもできます。"

これにより、2 つの代替昇格が提供されます。基になる型への昇格と、昇格された基になる型への昇格です。したがって、この段落だけでは、オーバーロードされた関数への関数呼び出しを解決するときに、これらの代替手段のどれを使用する必要があるかについて、あいまいさが生じます。

次に、パラグラフ 13.3.3 で、「変換シーケンス」に関してオーバーロード セットの実行可能な最適な関数を決定します。特に、この問題に関連するのは 13.3.3.1 (「暗黙の変換シーケンス」) であり、より具体的には 13.3.3.1.1 (「標準変換シーケンス」) であり、これらの変換シーケンスがどのような基本ステップで構成されているかを定義しています。

13.3.3.1.1/1 および表 12 では、これらのステップを 4 つのカテゴリ (昇格変換) に分類し、これらのシーケンスを構成する個々の変換のカテゴリに基づいて変換シーケンスをランク付けしています。

この場合、 1 つのプロモーションステップで構成される 2 つの 1 つの長さの変換シーケンスがあります(どちらも 4.5./4 で許可されています)。

変換シーケンスは、13.3.3.2 に従ってランク付けされます。特に、13.3.3.2/3 は、次の場合、変換シーケンス S1 が変換シーケンス S2 よりも好ましいと述べています。

「S1 のランク[つまり、プロモーション、変換など]が S2のランクよりも優れているか、S1 と S2 が同じランクであり、以下の段落のルールによって区別できるか、そうでない場合は [.. .]"

言及されている「以下の段落」は13.3.3.2/4であり、次のように述べています。

「標準のコンバージョン シーケンスはランクによって並べ替えられます。完全一致はプロモーションよりも優れたコンバージョンであり、プロモーションはコンバージョンよりも優れたコンバージョンです。次のルールのいずれかが適用されない限り、同じランクの 2 つのコンバージョン シーケンスを区別することはできません。」

次に、私たちの状況には当てはまらない一連のルールを次に示します。

したがって、同じランクの 1 つのプロモーションで構成される 2 つのワンステップ変換シーケンスがあります。上記の現在の標準の解釈によれば、呼び出しはあいまいでなければなりません

ただし、個人的には、スコープのない列挙型の基になる固定型への変換を、他の可能な変換よりも好ましいものにするために変更が必要であることに同意します。

于 2013-01-08T13:42:58.633 に答える