【问题标题】:Is this a bug in GCC?这是 GCC 中的错误吗?
【发布时间】:2013-05-04 11:35:29
【问题描述】:

编辑:这不是错误,只是我不知道dependent name lookups in templated base classes(MSVC“有用地”解决了没有错误)。


不久前我写了一个仿函数实现,以及一个使用它的简单“事件”包装器。它在 MSVC 下编译得很好,但是 GCC 给出了一个关于基类中的成员变量 subscribers 的错误,它没有被声明;将subscribers 更改为this->subscribers 可以解决问题(!)。它似乎只发生在奇怪地重复出现的模板模式和部分模板专业化中。

简化的源代码(对不起,令人费解的模板用法...):

#include <vector>

template<typename TEvent>
struct EventBase
{
protected:
        std::vector<int> subscribers;
};

template<typename TArg1 = void, typename TArg2 = void>
struct Event : public EventBase<Event<TArg1, TArg2> >
{
        void trigger(TArg1 arg1, TArg2 arg2) const
        {
                // Error on next line
                auto it = subscribers.cbegin();
        }
};

template<typename TArg1>
struct Event<TArg1, void> : public EventBase<Event<TArg1> >
{
        void trigger(TArg1 arg1) const
        {
                // Using `this` fixes error(?!)
                auto it = this->subscribers.cbegin();
        }
};

template<>
struct Event<void, void> : public EventBase<Event<> >
{
        void trigger() const
        {
                // No error here even without `this`, for some reason!
                auto it = subscribers.cbegin();
        }
};

int main()
{
        return 0;
}

我是否在某处调用了未定义的行为?我的语法有什么错误吗?这真的是 GCC 中的错误吗?它可能是一个已知的错误吗?任何见解将不胜感激!

更多细节:使用g++ -std=c++11 main.cpp 编译。我正在使用 GCC 版本 4.7.2。确切的错误信息:

main.cpp: In member function ‘void Event<TArg1, TArg2>::trigger(TArg1, TArg2) const’:
main.cpp:17:15: error: ‘subscribers’ was not declared in this scope

【问题讨论】:

  • 我也遇到过这种情况。根据经验,如果涉及模板,请始终信任 gcc 而不是 msvc(我发现 gcc 在 99.9% 的情况下是正确的)。
  • @JesseGood 甚至还有来自另一个 MSVC 难民的重复 SO question。显然,gcc 在 3.4 版本中修复了它,在此过程中破坏了一些旧代码。但是,嘿,谁说供应商需要 bug 兼容性作为卖点?

标签: c++ templates visual-c++ gcc name-lookup


【解决方案1】:

这是 MSVC 中的错误。依赖基类的名称必须是“thisambiguated”。

原因是从属名称proceeds in two phases 的非限定查找。在第一阶段,基类还不知道,编译器无法解析名称。 MSVC 不实现两阶段名称查找,并将查找延迟到第二阶段。

完整的专业化

template<>
struct Event<void, void> : public EventBase<Event<> >
{
        void trigger() const
        {
                // No error here even without `this`, for some reason!
                auto it = subscribers.cbegin();
        }
};

不会遇到这个问题,因为类和它的基类都是普通类,不是类模板,一开始就没有模板依赖。

当将 C++ 代码从 MSVC 移植到 gcc/Clang 时,依赖名称查找消歧和 template keyword disambiguation(即使用 ::template-&gt;template.template 语法调用成员函数模板)是您需要注意的两个细微之处必须处理(empty base optimization 是另一个)。对于所有标准合规性言论,出于向后兼容性的原因,这可能永远不会得到解决。

【讨论】:

  • 您能进一步解释一下吗?为什么在最后一种情况下不是错误? (很好的双关语。)
  • @Cameron:最后一个案例不是模板,它是一个完整的专业化。关于它的一切在编译时都是已知的。
  • @Cameron C++ FAQ 有一个explanation 说明为什么在这种情况下需要this-&gt;。它适用于 MSVC,因为它没有实现模板的两阶段名称查找。
  • 啊哈,谢谢大家。愚蠢地对编译器错误下结论。另一个我不知道存在的 C++ 角落 :-)
  • @Cameron 我也被这个咬过!
猜你喜欢
  • 2017-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-18
  • 1970-01-01
  • 1970-01-01
  • 2011-05-21
相关资源
最近更新 更多