这是GCC中的错误吗?

时间:2013-05-09 21:08:59

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

编辑:这不是一个错误,只是我不知道dependent name lookups in templated base classes(哪个MSVC“有帮助”解决而没有错误。)


我前段时间写了一个functor实现,还有一个使用它的简单“Event”包装器。它在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;
}

我是否在某处调用未定义的行为?我的语法有点错吗?这真的是海湾合作委员会的一个错误吗?它可能是一个已知的bug吗?任何见解都将不胜感激!

更多详细信息:使用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

1 个答案:

答案 0 :(得分:9)

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

原因是对从属名称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->template.template语法调用成员函数模板)是你必须处理的两个微妙之处(empty base optimization是另一个)。对于所有符合标准的修辞,由于向后兼容性原因,这可能永远不会得到解决。