2016-09-05 6 views
2

Рассмотрим C++ код:Почему я не могу использовать псевдоним из базового класса в производном классе с шаблонами?

template<typename Session> 
class Step 
{ 
public: 
    using Session_ptr = boost::shared_ptr<Session>; 
protected: 
    Session_ptr m_session; 
public: 
    inline Step(Session_ptr session) : 
     m_session(session) 
    {} 

}; 

template<typename Socket> 
class Session 
{ 
public: 
    Socket a; 

    Session(Socket _a): 
     a(_a) 
    {} 
}; 

template <typename Socket> 
class StartSession : public Step<Session<Socket> > 
{ 
protected: 
    Session_ptr m_session; //Unknown type Session_ptr 
public: 
    inline StartSession(Session_ptr session) : 
     Step<Session<Socket> >(session) 
    {} 

    void operator()(const boost::system::error_code& ec); 
}; 

template <typename Socket> 
class StartSession2 : public Step<Session<Socket> > 
{ 
protected: 
    typename Step<Session<Socket> >::Session_ptr m_session; 
public: 
    inline StartSession2(typename Step<Session<Socket> >::Session_ptr session) : 
     Step<Session<Socket> >(session) 
    {} 

    void operator()(const boost::system::error_code& ec); 
}; 

int main(int argc, char * argv[]) 
{ 
    Step<Session<int> >::Session_ptr b(new Session<int>(5)); //no problem 
    StartSession<int >::Session_ptr bb(new Session<int>(5)); //gcc ok, clang refuses to remember the symbol since the class has errors 
    StartSession2<int >::Session_ptr bbb(new Session<int>(5)); //no problem 
    std::cout << b->a; // ok 
    std::cout << bb->a; // gcc ok, clang bb not declared 
    std::cout << bbb->a; // ok 
    return 0; 
} 

Как вы можете видеть, есть какие-то странные (для меня по крайней мере) вещи здесь происходит ...

Во-первых, почему не Session_ptr доступны в ребенка классы? Я знаю, потому что они шаблонный класс, которые делают вещи более сложными ... Но я не вижу никакой двусмысленности здесь, что делает использование typename обязательного ...

Тогда, почему в основном, Session_ptr доступен либо как член базового класса, либо как член дочернего класса?

ответ

2

Неквалифицированный поиск не относится к зависимым базовым классам в шаблонах классов.

Так вот:

template <typename Socket> 
class StartSession : public Step<Session<Socket> > 
{ 
protected: 
    Session_ptr m_session; // <== unqualified name lookup on Session_ptr 
    // ... 
}; 

Step<Session<Socket>> является зависимой базового класса StartSession<Socket>. Для задачи поиска там, вы должны сделать квалифицированный поиск имя (что вы делаете в StartSession2):

template <typename Socket> 
class StartSession : public Step<Session<Socket> > 
{ 
protected: 
    typename Step<Session<Socket>>::Session_ptr m_session; 
    // ... 
}; 

Или просто добавьте псевдоним себя:

using Session_ptr = typename Step<Session<Socket>>::Session_ptr; 
2

Это связано с тем, что в классе StartSession ваш тип Session_ptr рассматривается как не зависящее от него имя, поэтому он просматривается без усталости базового класса, который зависит. Именно поэтому вам необходимо сделать ссылку на это имя зависимых некоторые, как, например, квалифицируя его образом, г ++ предполагает в предупреждениях:

note: (perhaps 'typename Step<Session<Socket> >::Session_ptr' was intended) 

кстати. некоторые компиляторы, такие как Visual Studio (я проверил его с 2015 года), с удовольствием скомпилируют ваш код. Это связано с тем, что VS не реализует надлежащим образом двухэтапный экземпляр шаблона. См. Здесь дополнительные сведения: What exactly is "broken" with Microsoft Visual C++'s two-phase template instantiation?

Смежные вопросы