10

重複の可能性:
const 引数を持つ関数とオーバーロード

オーバーロードと const 宣言の規則にかなり混乱しています。ここに私を困惑させる 2 つの事柄があります。私の頭の中のより深い誤解を見つけるのを手伝ってくれるかもしれません。;)

創刊:

私のコンパイラはこれを許可します:

void f(int & x) {
  std::cout << "plain f" << std::endl;
}
void f(const int & x) {
  std::cout << "const f" << std::endl;
}

ただし、次の場合はコンパイル エラーが発生します (関数には既に本体があります)。

void f(int x) {
  std::cout << "plain f" << std::endl;
}
void f(const int x) {
  std::cout << "const f" << std::endl;
}

const は、渡されたオブジェクトが変更されておらず、2 番目のケースではとにかくコピーされていることをコンパイラに伝えるためだけにあると思っていたので、これは理にかなっていると思います。しかし、それが正しければ、なぜ const を使用して関数をオーバーロードできるのでしょうか?

言い換えれば、コンパイル バージョンを使用して、次のように関数を呼び出すとどうなりますか。

  int x1 = 5;
  const int x2 = 5;
  f(x1);
  f(x2);

「const f」の代わりに「plain f」と「const f」を 2 回取得することはできますか? どうやら私は const を使用して、参照が変更されないだけでなく、どの関数を呼び出すかをコンパイラに指示しているようです。「プレーン」バージョンを削除すると問題なく動作し、「const」バージョンを 2 回呼び出すため、これはさらに混乱します。

さて、私の実際の質問は何ですか?この動作の背後にあるアイデアが何であるかを知りたいです。そうしないと、記憶するのが非常に難しいからです。

4

2 に答える 2

4

n3337 13.1

[注:8.3.5で指定されているように、同等のパラメーター宣言を持つ関数宣言は同じ関数を宣言するため、オーバーロードすることはできません。fferは存在する場合と存在しない場合のみです。

—constおよび/またはvolatileのdi3が同等であるパラメーター宣言。つまり、どの関数が宣言、定義、または呼び出されているかを判別するときに、各パラメーター型のconstおよびvolatile型指定子は無視されます。[ 例:

typedef const int cInt;
int f(int);
int f(const int); // redeclaration of f(int)
int f(int) { /* ... */ } // definition of f(int)
int f(cInt) { /* ... */ } // error: redefinition of f(int)

—終了例]この方法では、パラメーター型仕様の最も外側のレベルにあるconstおよびvolatile型指定子のみが無視されます。パラメータ型仕様内に埋め込まれたconstおよびvolatile型指定子は重要であり、オーバーロードされた関数宣言を区別するために使用できます124。特に、任意の型Tの場合、「Tへのポインタ」、「const Tへのポインタ」、および「へのポインタ」 「volatileT」は、「Tへの参照」、「const Tへの参照」、「volatile Tへの参照」と同様に、別個のパラメーター型と見なされます。</ p>

于 2012-07-25T08:46:16.070 に答える
2

const は、渡されるオブジェクトが変更されていないことをコンパイラに伝えるためだけに存在すると思っていました.2番目のケースではとにかくコピーされます

あなたは正しいです。2 番目のケースではとにかくコピーさconstれ、呼び出し元に違いがないため、標準はそれを定義し、同じ署名void f(const int x)を持ちます。void f(int x)したがって、それらは衝突します。同じ関数を 2 回定義しようとしています。

最初のケースではとにかくコピーされずvoid f(const int &x)、署名void f(int &x)異なるためです。したがって、それらは過負荷になります。

最初のケースでは、 withのint&バージョンを引数として呼び出すことは禁止されています。これは、明示的なキャストが見えない const オブジェクトへの非 const 参照が作成されるためです。これを行うと、const システムの目的が無効になります (つまり、const セーフを破る場合は、キャストを使用して明示的に行う必要があります)。したがって、参照パラメーターを持つ関数の const および非 const オーバーロードを持つことは理にかなっています。fx2

2 番目のケースでは、コピー元の const-ness とコピー先の const-ness の間に関係はありません。const 変数を非 const 変数から初期化することも、非 const 変数を const 変数から初期化することもできます。これは問題を引き起こさず、const-safety を壊しません。fそのため、標準では、 の 2 つの「異なる」バージョンが実際には同じ関数であると定義することで、これを明確にしています。

于 2012-07-25T09:39:29.793 に答える