【问题标题】:Name lookup differences between g++ and MSVSg++ 和 MSVS 之间的名称查找差异
【发布时间】:2017-01-06 18:29:36
【问题描述】:

考虑这段代码:

#include <iostream>

namespace N {
    class A {};
    void f(A a) { std::cout << "N::f\n"; }
}

void f(int i) { std::cout << "::f\n"; }

template <typename T>
class Base {
  public:
    void f(T x) { std::cout << "Base::f\n"; }
};


template <typename T>
class X : public Base<T> {
  public:
    void g() {
        T t;
        f(t);
    }
};

int main()
{
    X<N::A> x1;
    x1.g();

    X<int> x2;
    x2.g();
}

该代码旨在研究名称查找在 C++ 中的工作原理。

如果我用 GNU C++(6.1.0 版)编译这个程序,它会打印:

N::f
::f

但如果我用 Microsoft Visual Studio 2015 编译它,它会打印:

Base::f
Base::f

哪个是正确的行为,为什么?

【问题讨论】:

  • 我不知道这个问题的答案,但我知道 Microsoft Visual Studio 的 C++ 编译器通常不符合标准。 (所以我的猜测是微软VS是错误的)
  • VS 2015 应该非常接近标准。经过快速检查后,Clang 似乎表现得像 GCC。所以在不知道细节的情况下,我也会假设 VS 是错误的。也许你在这里偶然发现了一个错误。

标签: c++ templates base-class name-lookup dependent-name


【解决方案1】:

g++ 在这里符合标准,而 Visual C++ 不符合:

14.6.2 从属名称 [temp.dep]

3 在类或类模板的定义中,a的范围 在不合格期间不检查依赖基类 (14.6.2.1) 名称查找在类模板的定义点或 成员或在类模板或成员的实例化期间。

f() 替换为this-&gt;f() 将找到基本成员。

【讨论】:

  • 谢谢你,TemplateRex。我想知道为什么 C++ 有这个规则。是不是因为模板特化可能会产生一个没有f 函数的Base 类?
  • @oz1cz 完全正确!在参考书 C++ Templates the Complete Guide 中有一个完整的段落(9.4.2.)。
【解决方案2】:

在函数g 的函数定义中,名称f 被认为是在类外部声明的函数(在类定义中,此名称未声明;f 是从属名称)。

template <typename T>
class X : public Base<T> {
  public:
    void g() {
        T t;
        f(t);
    }
};

所以编译器使用 ADL 查找。

但是如果要写一个成员函数的显式调用

class X : public Base<T> {
  public:
    void g() {
        T t;
        this->f(t);
    }
};

那么函数f的调用将被视为基类成员函数的调用..

因此,MS VC++ 2015 似乎有一个错误。

【讨论】:

  • 为什么f 被认为是在类范围之外声明的名称?这是正常的行为吗,如果在类外找不到任何东西,它只会退回到类范围内吗?
  • @NathanOliver 是模板派生类的特定行为。我手头没有 C++ 标准,因此无法获得相关报价。
  • 这很有趣。我得去看看。 g++ 似乎甚至不会因为this 无法编译而退回。
  • @NathanOliver 它证实了我所写的。名称 f 在类定义之外查找(因为在模板类定义中没有名称为 f 的成员)。
  • @NathanOliver 看到这个问题stackoverflow.com/questions/27178483/…
猜你喜欢
  • 2016-07-12
  • 1970-01-01
  • 2015-03-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-07-12
  • 2015-03-19
  • 1970-01-01
相关资源
最近更新 更多