当前位置:网站首页>Core knowledge of C + + 11-17 template (13) -- name query and ADL

Core knowledge of C + + 11-17 template (13) -- name query and ADL

2020-12-06 01:54:22 itread01

- [ Name classification ](# Name classification ) - [ Name search ](# Name search ) - [ordinary lookup](#ordinary-lookup) - [ADL (Argument-Dependent Lookup)](#adl-argument-dependent-lookup) - [ An example of the official website ](# An example of the official website ) - [ADL The shortcomings of ](#adl The shortcomings of ) stay C++ in , If the compiler encounters a name , It looks for what the name stands for . such as x*y, If x and y It's the name of the variable , That's multiplication . If x Is the name of a type , Then it states an indicator . C++ It's a `context-sensitive` The language of : You have to know the context to know the meaning of the expression . What is the relationship between this and template ? To construct a template, you must know several contexts : * The context in which the template appears * The context in which the template is instantiated * Instantiate the context of template arguments ## Name classification Introduce two important concepts : * qualified name : The scope to which a name belongs ** Be explicitly specified **, for example `::`、`->` perhaps `.`.`this->count` It's just a qualified name, but count No , Because its scope is not indicated by the display , Even if it's with `this->count` It's equivalent . * dependent name: Depends on template arguments . for example :`std::vector ::iterator`. But if T Is an alias for a known type (using T = int), Then it's not dependent name. ![image](https://user-images.githubusercontent.com/14103319/101244818-7a5a3200-3743-11eb-8f54-129ea8f73ea1.png) ## Name search Name queries have a lot of details , Here we focus only on a few main points . ### ordinary lookup For qualified name Say , It will show the specified scope . If the scope is a class , Then base classes will be taken into account , But the outer scope of a class is not considered : ```c++ int x; class B { public: int i; }; class D : public B {}; void f(D *pd) { pd->i = 3; // finds B::i D::x = 2; // ERROR: does not find ::x in the enclosing scope } ``` This is very intuitive . contrary , On non qualified name Say , It will query layer by layer in the peripheral scope ( If in a class member function , The scope of this class and base class will be found first ).** This is called ordinary lookup** : ```c++ extern int count; // #1 int lookup_example(int count) // #2 { if (count < 0) { int count = 1; // #3 lookup_example(count); // unqualified count refers to #3 } return count + ::count; // the first (unqualified) count refers to #2 ; } // the second (qualified) count refers to #1 ``` This example is also intuitive . But the following example is not so normal : ```c++ template T max (T a, T b) { return b < a ? a : b; } namespace BigMath { class BigNumber { ... }; bool operator < (BigNumber const&, BigNumber const&); ... } using BigMath::BigNumber; void g (BigNumber const& a, BigNumber const& b) { ... BigNumber x = ::max(a,b); ... } ``` The problem here is : When calling max When ,`ordinary lookup` You won't find BigNumber Of `operator <`. If there are no special rules , Then C++ namespace In the scene , Will greatly limit the adaptability of the template .**ADL That's the special rule , To solve this kind of problem .** ### ADL (Argument-Dependent Lookup) ADL Appears in C++98/C++03 in , It's also called Koenig lookup, Apply to non qualified name On ( Hereinafter referred to as unqualified name).** stay [ Function calls expression ](https://en.cppreference.com/w/cpp/language/operator_other) in (f(a1, a2, a3, ... ), Contains implicit call overload operator, for example << ),ADL Apply a set of rules to query `unqualified function names`.** ADL It will change the parameter in the function expression `associated namespaces` and `associated classes` Add to query scope , That's why it's called **Argument-Dependent** Lookup. for example : A type points to class X Indicators of , So it's `associated namespaces` and `associated classes` It will contain X and X Of any of the following class and namespace. For a given type ,`associated classes` and `associated namespaces` Define according to certain rules , You can have a look at [ Official website Argument-dependent lookup](https://en.cppreference.com/w/cpp/language/adl), It's a little bit more , It's not written here . Understand why ADL、 When to apply to ADL When , According to the corresponding scene to check on the line ~ An additional point to note is ,ADL Ignored using : ```c++ #include namespace X { template void f(T); } namespace N { using namespace X; enum E { e1 }; void f(E) { std::cout << "N::f(N::E) called\n"; } } // namespace N void f(int) { std::cout << "::f(int) called\n"; } int main() { ::f(N::e1); // qualified function name: no ADL f(N::e1); // ordinary lookup finds ::f() and ADL finds N::f(), the latter is preferred } ``` `namespace N` Medium `using namespace X` Will be ADL Ignore , So in main In function ,X::f() It won't be considered . ### An example of the official website look down [ Official website ](https://en.cppreference.com/w/cpp/language/adl) Examples of how to understand : ```c++ #include int main() { std::cout << "Test\n"; // There is no operator<< in global namespace, but ADL // examines std namespace because the left argument is in // std and finds std::operator<<(std::ostream&, const char*) operator<<(std::cout, "Test\n"); // same, using function call notation // however, std::cout << endl; // Error: 'endl' is not declared in this namespace. // This is not a function call to endl(), so ADL does not apply endl(std::cout); // OK: this is a function call: ADL examines std namespace // because the argument of endl is in std, and finds std::endl (endl)(std::cout); // Error: 'endl' is not declared in this namespace. // The sub-expression (endl) is not a function call expression } ``` Pay attention to the last point `(endl)(std::cout);`, If the name of a function is enclosed in parentheses , That doesn't apply either ADL. One more : ```c++ namespace A { struct X; struct Y; void f(int); void g(X); } namespace B { void f(int i) { f(i); // calls B::f (endless recursion) } void g(A::X x) { g(x); // Error: ambiguous between B::g (ordinary lookup) // and A::g (argument-dependent lookup) } void h(A::Y y) { h(y); // calls B::h (endless recursion): ADL examines the A namespace // but finds no A::h, so only B::h from ordinary lookup is used } } ``` This is easier to understand , No explanation . ### ADL The shortcomings of Rely on ADL It may lead to semantic problems , This is also why it is necessary to add `::`, Or it is generally recommended to use xxx::func, instead of using namespace xxx . Because the former is qualified name, No ADL The process of . quote [ Modern C++ And ADL](https://blog.csdn.net/guangcheng0312q/article/details/103750458) Examples in , Just look at swap Just go , Other functions of the class can be omitted : ```c++ #include namespace A { template class smart_ptr { public: smart_ptr() noexcept : ptr_(nullptr) { } smart_ptr(const T &ptr) noexcept : ptr_(new T(ptr)) { } smart_ptr(smart_ptr &rhs) noexcept { ptr_ = rhs.release(); // Release ownership , Now rhs Of ptr_ The index is nullptr } smart_ptr &operator=(smart_ptr rhs) noexcept { swap(rhs); return *this; } void swap(smart_ptr &rhs) noexcept { // noexcept == throw() Make sure not to throw abnormally using std::swap; swap(ptr_, rhs.ptr_); } T *release() noexcept { T *ptr = ptr_; ptr_ = nullptr; return ptr; } T *get() const noexcept { return ptr_; } private: T *ptr_; }; // Provide a non member swap Function for ADL(Argument Dependent Lookup) template void swap(A::smart_ptr &lhs, A::smart_ptr &rhs) noexcept { lhs.swap(rhs); } } // Open this comment , Will trigger ADL Conflict //namespace std { // // Provide a non member swap Function for ADL(Argument Dependent Lookup) // template // void swap(A::smart_ptr &lhs, A::smart_ptr &rhs) noexcept { // lhs.swap(rhs); // } // //} int main() { using std::swap; A::smart_ptr s1("hello"), s2("world"); // Before exchange std::cout << *s1.get() << " " << *s2.get() << std::endl; swap(s1, s2); // Here swap Be able to pass through Koenig Search for, or say ADL According to s1 And s2 To query swap Function // After the exchange std::cout << *s1.get() << " " << *s2.get() << std::endl; } ``` ( End ) ** Friends can pay attention to my public number , Get the most up-to-date updates :** ![image](https://user-images.githubusercontent.com/14103319/92430320-11583200-f1c7-11ea-940d-1e297d2f394

版权声明
本文为[itread01]所创,转载请带上原文链接,感谢
https://chowdera.com/2020/12/20201206015149949k.html