Это ошибка в GCC?

EDIT: это не ошибка, только я не знаю о зависимых проверках имен в шаблонных базовых классах (какой 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;
}

Я вызываю поведение undefined где-то? Является ли мой синтаксис некорректным? Это действительно ошибка в 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

Ответ 1

Это ошибка в 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();
        }
};

не страдает от этой проблемы, потому что и класс, и его база - это обычные классы, а не шаблоны классов, и для начала нет зависимости от шаблона.

При переносе кода на С++ из MSVC в gcc/Clang, зависимостях поиска зависимых имен и template значения ключевых слов (т.е. вызов шаблона функции участника с помощью ::template, синтаксис ->template или .template) - это две из тонкостей, с которыми вам приходится иметь дело (пустая оптимизация базиса). Для всех риторики соответствия стандартам это, вероятно, никогда не будет исправлено по соображениям обратной совместимости.