考虑这个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
可以作为子类的成员作为子类的成员访问?
答案 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;
}