web-dev-qa-db-ja.com

BjarneはこのADLの例について間違っていますか、それともコンパイラのバグがありますか?

私は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であることを認識します。したがって、endlstdを探し、(<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がすでに述べたように、それは単なるタイプミスではありません。段落全体が(おそらく)間違っています。その本が他の(あまり知られていない)著者によるものであれば、私はこの種の誤りを受け入れることができますが、それがビャーネによって書かれたので、私は疑っていました(そして今でもそうです)。

81
maverik

コンパイラのバグではありません。 ADLはルックアップに使用されます関数ではなく引数operator<<は、パラメータstd::coutおよび(あるべき)std::endlを調べることによってここでADLを介して検出された関数です。

83
Peter Alexander

タイプミスだと言っている人にとっては、そうではありません。 Bjarneがミスを犯したか、コンパイラーがミスを犯しました。 OPによって投稿された段落の後の段落は

引数に依存するルックアップがないと、endlマニピュレータは見つかりません。そのまま、コンパイラは<<への最初の引数がstdで定義されたostreamであることを認識します。したがって、stdでendlを検索し、それを見つけます(in<iostream>)。

49
Lachlan Easton

他の人がすでに指摘しているように、それは本のタイプミスです。しかし、本の意味するところはそれです私たちは書く必要があります

_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が冗長性の削減にどのように役立つかを示しています。


gx _ for 私の間違いを指摘 に感謝します。

20
Ali

ヒントは、「引数依存のルックアップ」という名前にあります。

これは、修飾されていない関数名の検索であり、引数依存で機能します。

ルックアップとは何の関係もありませんfor引数。

ビャーネのミスポーク。

私は本を​​持っていませんが、これは本の誤りのようです。名前空間修飾子が欠落しているという事実は、ADLとは何の関係もありません。そのはず std::endl

8
Borgleader

はい、それはエラーです-例は形式が正しくなく、コンパイルすべきではありません。 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>_で)見つけます。

4
Andrew Tomazos