11

このコードがコンパイルされるとは思っていませんでしたが、コンパイルされます。私の理解では、func(d)「func」と呼ばれる関数のグローバル名前空間だけでなく、渡されたパラメーターの名前空間も検索します(引数依存の検索)

ただし、この場合、パラメーターはグローバル名前空間にあります。では、なぜ ns 名前空間で "func" が見つかるのでしょうか? パラメーターの型が typedef の場合、実際のパラメーターの名前空間ではなく、基になる型の名前空間を使用するという特別な規則はありますか?

これは本当のようですが、これをサポートするものは何も見つかりません...それは予想される動作ですか?

namespace ns
{
    struct data {};
    void func(ns::data item) {}
};

// Create an alias "datatype" in the global namespace for ns::data
typedef ns::data datatype;


int main()
{
    datatype d;
    func(d);
}
4

4 に答える 4

9

パラメータdは に対してローカルmainです。datatypeは type の単なるエイリアスであるため、 typens::datadありns::dataます。

ns::dataは名前空間の [直接] メンバーであるnsため、名前空間内のこの関数はnsADL と見なされます。

于 2012-11-02T10:01:46.127 に答える
6

他の回答は、根拠ではないにしても、すでに理由を提供しています。

Atypedefは型のエイリアスであり、コンパイラによって実際の型に解決されます。引数依存のルックアップは、typedef ではなく、基になる型に基づいて行われます。

この設計上の決定の論理的根拠は、実際には ADL が言語に含まれている理由です。演算子のオーバーロードをサポートするために、ADL が言語に追加されました。他のユースケースでは、ユーザーは関数の名前空間を明示的に指定できますが、演算子のオーバーロードの場合、直観に反する複雑なコードになります。

std::string s("Hi");
std::cout.operator<<(s); // or is it std::operator<<(std::cout,s)??

そのため、言語は、さまざまな名前空間、特に関数への引数の名前空間で演算子 (および関数) を検索するためのルックアップのルールを追加しました。この場合std::operator<<を取る がstd::stringのメンバーではない場合の内部ですstd::cout。同じ動作が同じ名前空間内のすべてのフリー関数に拡張されます (なぜでしょうか?) 型のインターフェイスにメンバー関数だけでなく、同じ名前空間内のフリー関数も含めることができます。

これに注目すると、目的は型のインターフェースの一部である関数にアクセスすることであり、それらは型で定義されいます。別の名前空間に typedef を追加すると、元の型を参照する省略表現が作成されるだけです。型で提供されたすべての関数 (たとえば、operator<<(std::ostream&,MyType)) は元の名前空間にあり、. の名前空間にはありませんtypedef。エイリアスが作成された場所ではなく、実際の型が定義された名前空間を ADL で調べたいとします。

于 2012-11-03T01:44:11.523 に答える
5

この動作は標準で指定されています(私の強調):

3.4.2 引数依存の名前検索 [basic.lookup.argdep]

2 -T関数呼び出しの引数の型ごとに、0 個以上の関連付けられた名前空間のセットと、考慮される 0 個以上の関連付けられたクラスのセットがあります。名前空間とクラスのセットは、関数の引数の型 (およびテンプレート テンプレート引数の名前空間) によって完全に決定されます。型を指定するために使用されるtypedef 名とusing 宣言は、このセットには寄与しません。

これは少し残念です。たとえば、コード (別の名前空間の typedef を使用して ADLから適応):

std::vector<int> v;
count(v.begin(), v.end(), 0);

の有効性と意味std::vector<T>::iteratorは、 が typedef に対するT *ものか、または の型に対するものかによって異なりますnamespace std

于 2012-11-02T10:34:46.833 に答える
4

注意すべき主なポイントは、 atypedefは新しい型を導入するのではなく、別の型のシノニムであるということです。typedも同様ns::dataです。

これで ADL が適用され、関数funcが名前空間で見つかりますns

追加: ADL を防ぐために、次のように書くことができます(func)(d)

于 2012-11-02T10:15:07.190 に答える