6

编辑:这不是一个错误,只是我不知道模板化基类中的依赖名称查找(MSVC“有用地”解决了没有错误)。


不久前我写了一个仿函数实现,以及一个使用它的简单“事件”包装器。它在 MSVC 下编译得很好,但是 GCC 给出了一个关于基类中的成员变量的错误subscribers,没有被声明;更改subscribersthis->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
4

1 回答 1

9

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

原因是从属名称的非限定查找分两个阶段进行。在第一阶段,基类还不知道,编译器无法解析名称。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关键字消歧::template(即使用,->template或语法调用成员函数模板.template)是您必须处理的两个微妙之处(空基优化是另一个)。对于所有标准合规性言论,出于向后兼容性的原因,这可能永远不会得到解决。

于 2013-05-09T21:10:08.410 回答