【问题标题】:Is clang or gcc correct about this inner class member access?关于这个内部类成员访问,clang 或 gcc 是否正确?
【发布时间】:2019-06-04 15:51:24
【问题描述】:

以下代码在 clang 上编译并运行,但在 gcc 上失败并显示“错误:非静态数据成员‘Outer::a’的无效使用”:

#include <functional>
#include <vector>
#include <assert.h>
#include <iostream>
#include <memory>

class Outer
{
public:
    bool a = false;

    virtual void f() = 0;

    template <typename T>
    class Inner : public T
    {
    public:
        virtual void f() override
        {
            a = true; // Note: accessed through inheritance, not through outer scope
        }
    };
};

struct Foo : Outer { };

int main()
{
    Outer::Inner<Foo> f;
    f.f();
}

将“this->a”添加到内部类使其适用于两个编译器,但我想知道正确的行为是什么以及标准对此有何规定。

有趣的是,上面的代码可以作为 VS2017 中更大代码库的一部分在工作中使用,但是当我在家里单独尝试使用 VS2017 时,它会失败,并出现与 GCC 相同的错误。

你可以尝试在这里编译:

【问题讨论】:

  • 如果您删除 main() 和 bool a 数据成员中的代码,则代码会在 clang 中失败(如果它是一致的,则不应该这样做)。所以我认为这是clang中的一个错误。
  • 也许用language-lawyer标签替换其中一个标签
  • 应该是 CLang 的错误。我不明白它怎么可能不是编译错误。
  • @NathanOliver 啊,我不是第一次意识到这一点。似乎 gcc 是正确的,那么问题是为什么 clang 允许它。您链接中的示例没有。

标签: c++ gcc clang language-lawyer


【解决方案1】:

此代码格式错误无需诊断。所以 Gcc 是正确和友好的。 Clang 和 MSVC 缺乏诊断只是编译器质量问题。

涉及的标准规则是[temp.res]/8:

可以在任何实例化之前检查模板的有效性。 [ 注意:知道哪些名称是类型名称允许以这种方式检查每个模板的语法。 —— 尾注 ] 该程序格式错误,不需要诊断,如果:

  • [..]

  • 由于不依赖于模板参数的构造或 [...]

在f body 中,不合格的id-expression a 不依赖于任何模板参数,所以这个id-expression 应该在模板的定义点被解析,而不需要知道任何模板参数。在这一点上,这个表达式是错误的。


注意:非限定的 id 表达式,(非类成员访问)表达式只有在命名该类或非依赖基 [temp.dep.type]/5 的成员时才应该是成员:

一个名字是当前实例化的成员,如果它是:

  • 一个非限定名称,在查找时,它指的是作为当前实例化的类的至少一个成员或其非依赖基类。

【讨论】:

  • 您是在暗示this is also ill formed,因为Outer::a 也不依赖于它的模板参数? Outer::a = 7 的有效性 确实 取决于 tempate 参数,但表达式不使用 T。因此,您的答案是否正确取决于标准所指的“不依赖于模板参数的构造”究竟是什么意思。
  • @Yakk-AdamNevraumont 我看到的链接代码与问题中的代码完全相同。
  • 修复了链接,抱歉
  • @Yakk-AdamNevraumont 我知道规则是仅当 id 表达式命名当前类的成员或非依赖基类的成员时才假定隐含对象参数。我可以在标准中寻找它。所以Outer::a和a根据这条规则是等价的。
  • @Yakk-AdamNevraumont 我找到了规则:temp.dep.type/5。
猜你喜欢
  • 2018-07-24
  • 2013-02-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多