1

重複の可能性:
戻り値の型は関数シグネチャの一部ですか?

関連するが接線的な質問 (戻り値の型だけが異なる関数テンプレートを明確にする方法は? ) のフォローアップとして、関数の戻り値の型が署名の一部と見なされないという事実に関連する質問をしたいと思います。関数の。

次のコードを検討してください。

#include <iostream>

int foo()
{
    return 0;
}

int main()
{
    long n = static_cast<long(&)()>(foo)(); // Error: incorrect return type
    int p = static_cast<int(&)()>(foo)(); // Compiles just fine 
}

上記のコード行では、キャスト先の関数型の戻り値の型が関数の戻り値の型とfoo一致しないため、コンパイル エラーが発生します。foo

しかし、関数の戻り値の型は、関数のシグネチャには関係ないと思いました!

ある考え方によれば、関数のシグネチャlong(&)()は のシグネチャと一致するため、この型の関数へfooの のキャストはfoo成功するはずです。

ただし、キャストは成功しません。理屈のどこがおかしい?関数シグネチャが原因でキャストが失敗できない場合、キャストが失敗するのはなぜですか?

4

4 に答える 4

8

戻り値の型が関数のシグネチャの一部を形成していないことは正しいです。

ただし、これは関数のの一部を形成するため、ポインターを互換性のない関数型に変換することはできません。

于 2012-12-03T14:45:30.610 に答える
4

戻り型型の一部ですが、過負荷の解決には使用されません。用語を混同しないことが重要です。基本的に、型には引数と戻り値が含まれますが、過負荷の解決中は、戻り型は考慮されません。関数または関数ポインタのタイプは、呼び出し元と呼び出し先の間の契約であり、条件に完全に同意する必要があります。

実用的な観点から、あなたが提案したことが許可された場合に何が起こるかを考えてください。呼び出し元がスペースを予約し、そのスペースへのポインターを関数に渡す呼び出し規約を想像してみてください。関数はその場所に返されたオブジェクトを作成します(これは実際には非常に一般的な呼び出し規約です)。提案したキャストと次のユースケースを実行することが許可されたと考えてください。

static_assert(sizeof(T1)<sizeof(T2));
T2 f();
T1 (*p)() = &f;

p();                                  // call

これで、コンパイラーが処理p()しているときに、どこかにスペースを予約し、関数のタイプを指定すると、予約する必要がありますsizeof(T1)。次に、関数を呼び出します。この関数は、オーバーフローの原因となる場所にバイトfを書き込む関数を呼び出すことになります。sizeof(T2)

サイズが一致していても、コードに問題があります。を検討T1==intT2==float、プラットフォームでsizeof(int)==sizeof(float)。上記のコードではバッファオーバーランは発生しませんが、戻り型の場所に格納されるビットパターンは、のビットパターンではなく、のビットパターンになりfloatますint

于 2012-12-03T14:52:05.607 に答える
1

関数の戻り値の型は署名の一部ではありませんが、関数ポインターまたは参照によって参照される関数を正しく呼び出すためにコンパイラーが知る必要があるのは署名ではありません。

パラメーターだけでなく、コンパイラーは戻り値の型を知る必要があります。これにより、スタックに戻り値用のスペースを作成したり、正しいレジスターから戻り値を読み取ったり、呼び出し規約が与えられた実装。

これが、戻り値の型が関数の型の一部である理由です。つまり、型は、関数を呼び出すコードを発行するためにコンパイル時に知る必要があることをコンパイラに伝えます。

関数long(&)()のシグネチャは foo のシグネチャと一致します

long(&)()は関数シグネチャではなく、typeです。foo(void)関数シグネチャ (の表現) です。これには、名前とパラメーターが含まれます。ただし、C++ コードで関数シグネチャを指定する必要はまったくありません (おそらく、渡された文字列などとしてdlsym)。関数シグネチャの決定的な表現は、特定の実装における関数の修飾名です。マングリング スキームは標準ではなく、実装次第です (ただし、異なる実装が互いのライブラリを呼び出したい場合は、同じスキームを使用する必要があるため、OS が指定する可能性があります)。

于 2012-12-03T16:32:29.843 に答える
0

関数の戻り型は、そのシグニチャー(およびその型)の一部と見なされますただし、戻り型が「共変」である場合は、異なる戻り型を持つ変数に関数ポインタを割り当てることができます。

于 2012-12-03T14:33:41.947 に答える