8

copy_if、transform など、単項関数またはバイナリ関数を最後の引数として受け取る C++ アルゴリズムを呼び出す場合、atoi や tolower などの C ライブラリ関数を渡すことができます。

たとえば、以下の呼び出しは正常に機能し、正しい出力が得られます (ideone で試行)

1) transform (foo, foo+5, bar, atoi);
2) transform (foo, foo+5, bar, ptr_fun(atoi));
3) transform(s.begin(),s.end(),s.begin(), static_cast<int (*)(int)>(tolower));

この使用法は、すべての C++ コンパイラで動作することが保証されていますか?

C++ で考える本には、「これは一部のコンパイラで動作しますが、必須ではありません」と記載されています。言及されている理由は、(私が理解しているように) transform は C++ 関数であり、最後の引数が同じ呼び出し規約を持つことを期待しているためです。

この本では、この問題の解決策として、このようなラッパー関数を別の cpp ファイルに作成し、iostreams ヘッダー ファイルをインクルードしないことも提案しています。

// tolower_wrapper.cpp
string strTolower(string s) {
  transform(s.begin(), s.end(), s.begin(), tolower);
  return s;
} 

これは問題なく動作しますが、呼び出し規約の問題がどのように解決されるかわかりませんでした。transform は引き続き C++ 関数であり、tolower は strTolower の C 関数であるため、この異なる呼び出し規則がここでどのように処理されるかを示します。

4

1 に答える 1

2

実際には質問の一部ではありませんが、これを読んでいる人に説明するのに役立つかもしれない最初の注意点は、アルゴリズムが関数ポインターまたは関数オブジェクトのいずれかを引数として取ることができるということです。

関数ポインターは、特定のパラメーターのセットを取り、特定の型を返すことを期待する関数へのポインターです。

関数オブジェクトは、operator() をオーバーライドしたクラスのインスタンスです。

アルゴリズム テンプレートを展開すると、コンパイラは 2 つのケースのどちらが適用されるかを判断し、適切な呼び出しコードを生成します。

アルゴリズムでバイナリ関数として使用されている C 関数の場合、それはユーザーが提供する関数ポインターです。宣言されている限り、C++ から C 関数を呼び出すことができますextern C { ... }

多くのコンパイラには、次のようなものを含む C ライブラリ関数のヘッダー ファイルが付属しています。

#ifdef  __cplusplus
extern "C" {
#endif

/* function declarations here */

#ifdef  __cplusplus
}
#endif

そのため、C++ プログラムから C ライブラリ ヘッダーをインクルードすると、含まれているすべての関数が魔法のように利用できるようになります。ただし、その部分は標準では保証されていません。そのため、あなたの本には、すべてのコンパイラで動作しない可能性があると記載されています。

別のしわは、関数ポインターを異なる言語リンケージを持つ型にキャストすることは許可されていないことです。これは、少なくともいくつかの例では実行していますが、一部のコンパイラーはとにかくそれを許可しているようです-たとえば、このGCC Bugを参照してください。

tolowerたとえば、特に適用されるもう1つの問題は、Cライブラリ関数の名前の一部がC++ stdライブラリの関数またはテンプレートの名前でもあることです。たとえば、 tolower という名前は にも定義されてい<locale>ます。この特定のケースについては、このGCC バグ レポートで説明されています。競合する宣言を含まない別のコンパイル単位でコンパイルされたラッパーを使用すると、この問題が解決されます。

于 2014-03-18T01:13:31.197 に答える