为什么我不能在带有模板的派生类中使用基类的别名?

时间:2016-09-05 15:59:32

标签: c++ templates c++11 type-alias

考虑这个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强制使用......

那么,为什么在main中,Session_ptr可以作为子类的成员作为子类的成员访问?

3 个答案:

答案 0 :(得分:6)

不合格的查找不会查找类模板中的从属基类。

所以这里:

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;

答案 1 :(得分:2)

这是因为在StartSession类中,您的Session_ptr类型被视为非依赖名称,因此正在查找依赖的基类的实例化。这就是为什么你需要引用这个名称取决于某些方法,例如通过g ++在警告中建议的方式对其进行限定:

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?

答案 2 :(得分:0)

在这里,我举另一个例子,介绍其他答案中已经给出的解决方案。

std::iterator<std::input_iterator_tag, MyType>Myterator<MyType>的从属基类。为了在那里查找,您必须进行合格的名称查找。

// std::iterator example  from http://www.cplusplus.com/reference/iterator/iterator/
//***************************************************************************************
#include <iostream>     // std::cout
#include <iterator>     // std::iterator, std::input_iterator_tag

template <class MyType>
class MyIterator : public std::iterator<std::input_iterator_tag, MyType>
{
  // The working alternatives, one per row
  //typename std::iterator<std::input_iterator_tag, MyType>::pointer  p;
  //using pointer = typename std::iterator<std::input_iterator_tag, MyType>::pointer; pointer p;
  //using typename std::iterator<std::input_iterator_tag, MyType>::pointer; pointer p;
  //using Iter = typename std::iterator<std::input_iterator_tag, MyType>; typename Iter::pointer p;
  pointer p; // This does not work while any of alternatives in comments above do work
public:
  MyIterator(MyType* x) :p(x) {}
  MyType& operator*() {return *p;}

};

int main () {
  int numbers[]={10,20,30,40,50};
  MyIterator<int> from(numbers);
  std::cout << *from << ' ';
  std::cout << '\n';

  return 0;
}
相关问题