私はC++プログラミング言語、第4版( Bjarne Stroustrup )について 引数に依存)を読んでいます-ルックアップ 。引用は次のとおりです(26.3.6、過度に攻撃的なADL):
引数に依存するルックアップ(ADLと呼ばれることが多い)は、冗長性を回避するのに非常に役立ちます(14.2.4)。例えば:
#include <iostream> int main() { std::cout << "Hello, world" << endl; // OK because of ADL }
引数に依存するルックアップがないと、
endl
マニピュレータは見つかりません。そのまま、コンパイラは<<
の最初の引数がostream
で定義されたstd
であることを認識します。したがって、endl
でstd
を探し、(<iostream>
で)見つけます。
そして、これが result コンパイラによって生成されます(C++ 11モード):
prog.cpp: In function ‘int main()’:
prog.cpp:4:36: error: ‘endl’ was not declared in this scope
std::cout << "Hello, world" << endl;
^
これはコンパイラまたは本のバグです。規格は何と言っていますか?
更新:
少し明確にする必要があります。正しい答えはstd::endl
を使用することです。質問は本の中のテキストについてでした。 Lachlan Eastonがすでに述べたように、それは単なるタイプミスではありません。段落全体が(おそらく)間違っています。その本が他の(あまり知られていない)著者によるものであれば、私はこの種の誤りを受け入れることができますが、それがビャーネによって書かれたので、私は疑っていました(そして今でもそうです)。
コンパイラのバグではありません。 ADLはルックアップに使用されます関数ではなく引数。 operator<<
は、パラメータstd::cout
および(あるべき)std::endl
を調べることによってここでADLを介して検出された関数です。
タイプミスだと言っている人にとっては、そうではありません。 Bjarneがミスを犯したか、コンパイラーがミスを犯しました。 OPによって投稿された段落の後の段落は
引数に依存するルックアップがないと、endlマニピュレータは見つかりません。そのまま、コンパイラは<<への最初の引数がstdで定義されたostreamであることを認識します。したがって、stdでendlを検索し、それを見つけます(in
<iostream>
)。
他の人がすでに指摘しているように、それは本のタイプミスです。しかし、本の意味するところはそれです私たちは書く必要があります
_std::operator<<(std::cout, "Hello, world").operator<<(std::endl);
_
ADLなし。それがBjarneが冗長性によって意味したことです。
私は正直に立っています。 Lachlan Easton が指摘しているように、これはタイプミスではなく、本の間違いです。私はこの本にアクセスできないので、その段落を読んで自分で理解することができませんでした。私はこの間違いをBjarneに報告し、彼がそれを修正できるようにしました。
おかしい。 同じ例はウィキペディアにあります そして
_
std::endl
_は関数ですが、_operator<<
_への引数として使用されるため、完全な修飾が必要であることに注意してください(_std::endl
_は関数ポインターであり、関数呼び出しではありません)。
間違いなく、それは本の間違いです。それにもかかわらず、例std::operator<<(std::cout, "Hello, world").operator<<(std::endl);
は、ADLが冗長性の削減にどのように役立つかを示しています。
ヒントは、「引数依存のルックアップ」という名前にあります。
これは、修飾されていない関数名の検索であり、引数で依存で機能します。
ルックアップとは何の関係もありませんfor引数。
ビャーネのミスポーク。
私は本を持っていませんが、これは本の誤りのようです。名前空間修飾子が欠落しているという事実は、ADLとは何の関係もありません。そのはず std::endl
。
はい、それはエラーです-例は形式が正しくなく、コンパイルすべきではありません。 ADLは、関数呼び出し式を導入する非修飾関数名に適用されます。 endl
は、_std::endl
_を検索しようとするID式です。 endl
は関数呼び出し式を導入しないため、引数依存のルックアップは使用されず、修飾されていないルックアップのみが使用されるため、意図したとおりに_std::endl
_が見つかりません。
より単純で正しい例は次のとおりです。
_#include <vector>
int main()
{
std::vector<int> x, y;
swap(x,y); // calls std::swap due to ADL
}
_
要約すると、修飾されていないID(たとえば、f
)を持つ関数呼び出し(たとえば、f(x,y,z)
)が検索される前に、まず関数のパラメーター(たとえば、_x,y,z
_)が分析されます。それらのタイプを決定します。関連する名前空間のリストは、タイプに基づいて形成されます(たとえば、タイプの定義を囲む名前空間は関連する名前空間です)。次に、これらの名前空間で関数がさらに検索されます。
Bjarneの例の意図は、_std::operator<<
_ではなく、_std::endl
_関数のADLを誇示することです。これには、オーバーロードされた演算子が実際には関数呼び出し式であるという追加の理解が必要です。したがって、_x << y
_はoperator<<(x,y)
を意味し、_operator<<
_は非修飾名であるため、ADLが適用されます。 LHSのタイプは_std::ostream
_であるため、std
は関連付けられた名前空間であり、したがってstd::operator<<(ostream&, ...)
が見つかります。
修正された解説は次のようになります。
引数依存のルックアップがないと、
std
名前空間でオーバーロードされた_<<
_演算子が見つかりません。そのまま、コンパイラは<<への最初の引数がstdで定義されたostreamであることを認識します。したがって、stdで演算子_<<
_を探し、(_<iostream>
_で)見つけます。