• C++模板编程(14)---名称查询(Looking Up Names)


    0.简介

        C++语言的名称搜寻机制设计众多细节,我们只集中在数个主要概念上,为了保证:

    1)通常情况下,这些查询符合人们的直觉;

    2)特别复杂的情况可以在C++standard中找到答案。

    受饰名称的查询范围是在其“修饰构件所处的作用域”(the scope implied by the qualifying construct)内。如果该作用域是个class,则其base class也将被查询。然而编译器查询受饰名称时,并不考虑圈封作用域enclosing scopes。下面的例子阐释了这个基本法则:

    int x;

    class B{

    public:

            int i;

    };

    class D: public B{};

    void f(D* pd)

    {

            pd->i =3; //编译器找到B::i(pd->i 是个 qualified name)

            D::x =2;  //Error, 在D作用域中(包括B)也找不到x

    }

    与之形成对比的是,编译器通常会依次在更外层的圈封作用域(more enclosing scopes)中查询非受饰名称unqualified names,尽管在成员函数定义内编译器会先查询class作用域和base class作用域,然后才是其他圈封作用域。这便是所谓的ordinary lookup(常规查询)。

    下面例子展示ordinary lookup的基本概念:

    extern int count;  //(1)

    int lookup_example(int count) //(2)

    {

            if(count < 0) {

                    int count = 1;   //(3)

                    lookup_example(count); // 非受饰的count的代表是(3)

            }

            return count += ::count; //第一个count(非受饰)代表(2)

                                                    //第二个::count(受饰)代表(1)

    }

    在常规查询之外,还有一种用法来查询非受饰名称unqualified names.这种机制有时也称为依赖于实参的查询,argument-dependent lookup,ADL。深入ADL之前,先介绍要给引发此机制的例子:

    template <typename T>

    inline T const & max (T const&, a, T const& b)

    {

            return a<b ? b:a;

    }

    现在假设我们需要把这个template应用到定义于另一个namespace内的类型身上:

    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);

            ...

    }

    这里的问题在于:max() template 对BigMath namespace一无所知,而ordinary lookup常规查询机制无法找到一个operator < 可施行于BigNumber类型。如果没有某种特殊规则,这个问题就大大缩减了templates在C++ namespaces 情形下的应用性。一个解决办法就是ADL。

    1.依赖于实参的查询Argument-Dependent Lookup, ADL

    ADL只适用于这样的非受饰名称unqualified names:在函数调用动作中用到的一个非成员函数名称。如果ordinary lookup可找到一个成员函数名称或一个类型名称,编译器就不启动ADL。如果被调用函数的名称被写进一对小括号内,ADL也不起作用。

    #include <iostream>

    namespace X {

            template<typename T> void f(T);

    }

    namespace N {

            using namespace X;

            enum E {e1};

            void f(E) {

                   std::cout << "N::f(N::E) called" << std::endl;

            }

    }

    void f(int)

    {

            std::cout << "::f(int ) called" << std::endl;

    }

    int main()

    {

            ::f(N::ee1); //受饰函数名称,不使用ADL

            f(N::e1); // ordinary lookup,找到::f,而ADL找到N::f(),编译器会优先考虑后者

    }

    这个例子中, ADL机制中的namespace N中的using指令被忽略。因此main()中的f()不会被编译器认为是对X::f()调用。

    2.友元名称植入Friend Name Inject

    3. 植入类名称Injected Class Names

  • 相关阅读:
    “箭在弦上”的边缘计算,更需要冷静和智慧
    【多目标优化算法MOAHA】多目标人工蜂鸟算法(Matlab代码实现)
    JS Array 操作方法合集
    洛谷 P5058 [ZJOI2004]嗅探器(割点)
    一看就懂:这就是机器学习过程!
    C# Fleck Socket
    dbeaver连接MySQL数据库及错误Connection refusedconnect处理
    Ubuntu安装NVIDIA显卡驱动
    KingbaseES 数据库连接
    final 在 java 中有什么作用?
  • 原文地址:https://blog.csdn.net/zkmrobot/article/details/125612116