zoukankan      html  css  js  c++  java
  • Step By Step(C++模板解析)

    一、符号查找:

        这里先给出两个基本的术语,它们将在后面的篇节中被广泛的引用。
        1. 限定作用域符号:
        如果一个名称(函数名、类名或变量名)的前面包含域解析运算符(::),或成员访问运算符(. or ->),这表明该名称将属于某一作用域,那么我们就将该类名称成为限定作用域符号。如:::GetTickCount()、myClass->GetCount()等。与其相反的我们则成为非限定作用域符号,如:GetCount(),GetTickCount()等。
        
        2. 依赖型符号:
        如果一个名称依赖于某个模板参数,如:vector<T>::iterator,这里由于T是一个模板参数,同时也是一个未知类型,因此我们可以称iterator为依赖型符号,如果改为vector<int>::iterator,那么这里的iterator将不再为依赖型符号了。
        C++编译器在进行编译时,需要对一些符号进行查找,以确认其身份是否合法。对于限定作用域的符号,它的查找范围相对有限,如类成员变量,它的查找范围将仅限于当前类、父类等。见如下代码示例和关键性注释:

     1     #include <stdio.h>
     2     
     3     int i;
     4     class Base {
     5     public:
     6         Base() : i(0) {}
     7     protected:
     8         int i;
     9     };
    10     
    11     class Derive : public Base {
    12     public:
    13         void DoTest() {
    14             //符号i的搜索范围将仅限于当前类和其基类Base。
    15             printf("The value of i is %d.\n",this->i);
    16         }
    17     };
    18     
    19     int main() {
    20         Derive d;
    21         d.DoTest();
    22         return 0;
    23     }

        然而对于非限定作用域符号的查找则没有此类的限制,基本的查找规则为由内到外逐层查找,即先查找类内和父类范围内,如果均为找到,在查找类的外部,如果在外部仍为找到,C++编译器将会启用ADL(参数依赖查找)规则。现在我们还是通过示例来讲清楚这个复杂的概念吧。

        template<typename T>
        T const& max(T const& a, T const& b) {
            return a < b ? b : a;
        }
        namespace BigMath {
            class BigNumber {
                ... ... 
            }
            bool operator<(BigNumber const&, BigNumber const&);
        }
        using BigMath::BigNumber;
        void f(BigNumber const& a, BigNumber const& b) {
            ... ... 
            BigNumber c = max(a,b);
        }

    二、ADL(Argument-Dependent Lookup):
        
        首先明确一下,ADL只能应用于非限定作用域符号。C++编译器的符号查找范围将会根据函数的实参进一步扩大,即实参所关联的类和名字关键都将成为本次符号查找的考虑范围了。其基本规则如下:
        1. 对于基本类型,其范围为空集。
        2. 对于指针和数组,其范围为指针或数组类型所关联的类和名字空间。
        3. 对于枚举类型,仅为该枚举声明所在的名字空间。
        4. 对于类类型,将包括类本身和直接基类,以及他们所在的名字空间,如果是模板类,还将包括模板类实例化后模板实参所关联的类和所在的名字空间。
        5. 对于函数,将包括其实参和返回值所关联的类和其所属的名字空间。
        6. 对于类成员指针,除了其外围类之外,还将包括该指针类型所关联的类和名字空间。
        综上所述,我们就可以很容易的理解上面的代码示例了,由于f()函数的参数为BigNumber,编译器在搜索BigNumber的operator<(...)时会考虑到BigNumber所在的名字空间,这样就可以定位到与BigNumber对应的operator<(...)函数了。
        
    三、模板解析:

        这里着重讨论的是template关键字的另外一种应用场景,见如下示例代码和关键性注释:

     1     #include <stdio.h>
     2     
     3     template<typename T>
     4     class InnerClass {
     5     public:
     6         static void DoTest() { 
     7             printf("This is InterClass::DoTest().\n"); 
     8         }
     9     };
    10     
    11     template<typename T>
    12     class OuterClass {
    13     public:
    14         template<typename T2>
    15         void func() {
    16             T2::DoTest();
    17         }
    18     };
    19     
    20     template<typename T> 
    21     void DoTest(OuterClass<T>& outClass) {
    22         //限定符.前面的变量outClass的类型依赖于模板参数,而其后面的限定符也是一个
    23         //模板符号,在这种情况下,为了使编译器能够确切的清楚func符号的类型,我们
    24         //需要在.和func之间插入template关键字,以明确告诉编译器func的类型。
    25         outClass.template func<InnerClass<T> >();
    26     }
    27     
    28     int main() {
    29         OuterClass<int> outClass;
    30         DoTest(outClass);
    31         return 0;
    32     }
  • 相关阅读:
    nginx限速 原理
    规则引擎 图形界面
    阿里巴巴 规则引擎
    martinfowler Data Guide big data bad things
    Nginx Request URI too large
    linux2.6.30.4内核移植(1)
    根文件系统
    Linux内核配置:定制配置选项
    Linux内核配置:Kconfig
    Linux内核配置:Makefile目标
  • 原文地址:https://www.cnblogs.com/orangeform/p/2616583.html
Copyright © 2011-2022 走看看