为什么不能在派生类中使用基类中的别名和模板?
Why can't I use alias from a base class in a derived class with templates?
考虑下面的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
既可以作为基类的成员也可以作为子类的成员访问呢?
不限定查找不会查找类模板中的依赖基类。
这里:
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;
这是因为在StartSession
类中,您的Session_ptr
类型被视为非依赖名称,因此它正在与依赖的基类的安装一起查找。这就是为什么您需要以某种方式依赖于此名称的原因,例如,通过像g++在警告中建议的那样对其进行限定:
note: (perhaps 'typename Step<Session<Socket> >::Session_ptr' was intended)
顺便说一句。像Visual Studio这样的编译器(我现在用2015年检查过了)会很高兴地编译你的代码。这是因为VS没有正确地实现两阶段模板实例化。更多信息请看这里:"坏了"到底是什么?与Microsoft Visual c++ 's两阶段模板实例化?
这里我再举一个例子,在其他答案中已经给出了解决方案。
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;
}
相关文章:
- std::具有相同基类的类的变体
- 是否可以初始化不可复制类型的成员变量(或基类)
- 在C++中,是否可以基于给定的标识符创建基类的新实例,反之亦然
- 基类中的函数名称解析
- C++初始化基类
- 如何通过派生类函数更改基类中的向量
- 如何定义一个纯抽象基类
- 将空基类优化对象强制转换为另一种类型是否会破坏严格的别名?
- 为什么派生类找不到基类的类型别名?
- 为什么我不能为位于基类中的类中的类型设置别名
- 模板基类函数成员的别名
- 我可以给派生类中基类的成员取别名吗
- 在模板基类列表中使用类本地类型别名
- 基类方法别名
- 在不增加类内存的情况下,我可以为派生类中基类的成员别名吗
- 在基类子句中使用类中定义的typedefs/type别名
- 使用别名模板时,无法将"std::unique_ptr"分配给 clang 中的基类
- 当基类具有两个或多个模板参数时,C++11 别名基模板类变量在模板派生类中不起作用
- 为什么不能在派生类中使用基类中的别名和模板?
- 在不同的命名空间中调用别名声明的基类构造函数