5

次のコード スニペットがあるとします。

#include <string>
#include <iostream>

int main()
{
    std::string prefix("->"), middle(), suffix("<-");
    std::cout << "Test: " << prefix << middle << suffix << std::endl;

    return 0;
}

上級 C++ プログラマーは、がのデフォルト ctormiddle()を呼び出しているのではなく、関数宣言であることがすぐにわかります。std::string

興味深いのは、gcc が次の出力を生成するのはなぜですか。

Test: ->1<-

Visual Studio のリンカー エラーとは対照的に? ここで何が起こっているか知っている人はいますか?

4

2 に答える 2

7

boolwith を使用すると、関数ポインタが に変換されcoutます。

関数ポインターがvoid *暗黙的に変換されないのはなぜですか。これは演算子 << がオーバーロードするものですか? 関数ポインターはオブジェクトポインターではないためです。

C++11 §4.10/2:

「cv T へのポインター」型 (T はオブジェクト型) の prvalue は、「cv void へのポインター」型の prvalue に変換できます。「cv T へのポインター」を「cv void へのポインター」に変換した結果は、オブジェクトが型 T の最派生オブジェクト (1.8) であるかのように、型 T のオブジェクトが存在する格納場所の先頭を指します。 (つまり、基本クラスのサブオブジェクトではありません)。null ポインター値は、変換先の型の null ポインター値に変換されます。

于 2013-08-03T01:06:58.820 に答える
1

Yuが言ったように、関数ポインタはに変換されていboolます。

g++ オプティマイザーは明らかに変換を事前に評価していますが、Visual C++ は関数アドレスが null であるかどうかをテストするコードを実際に生成します。これにはリンカーが関数アドレスを提供する必要があります。

ルールは

すべてのプログラムには、そのプログラムで ODR で使用されるすべての非インライン関数または変数の定義が 1 つだけ含まれている必要があります。診断は必要ありません。

アドレスを使用しているため、関数odr-usedです。定義を提供しないことは、このルールに違反していることになります。また、標準では診断が必要ありません。つまり、ツールチェーンは必要なことを自由に行うことができます。

必須ではありませんが、Visual C++ は診断を生成しています。

g++ はbool、関数ポインターへの実際の関数の減衰がヌル関数ポインターを生成することは決してないことを知っているため、変換の実際の結果を に与えています。

ただし、ハード ドライブをフォーマットすることも同様に有効です。なぜなら、ツールチェーンがここでできることとできないことを標準が述べていないからです。

于 2013-08-03T01:15:45.407 に答える