[英]Using nested class as parent class template parameter?
我有一个嵌套的 class 定义,我想作为父 class( class 包含嵌套的 class,而不是被继承的 class )模板参数传递下去。 由于模板似乎不知道嵌套类的存在,我试图将其作为不完整的类型传递下去,后来才发现这样做通常是个坏主意,而且很少被允许(例如shared_ptr
)。
我知道这可以很容易地通过简单地在外部声明嵌套的 class 来解决(我就是这样做的),但我问这个是因为我想了解是否有任何方法可以达到同样的效果,因为我喜欢他们的做法不要污染命名空间它们如何与父 class 定义“关联”而不暴露任何内容。
这是一个示例,也许可以使我在谈论的内容更加清楚:
#include <memory>
using namespace std;
template <class T> class shared_class {
protected:
shared_ptr<T> d = make_shared<T>();
T* container() { return d.get(); }
};
// A is the "parent" class.
class A : public shared_class<C> { // Compiler error: C is undefined.
// Similarly, A::C will complain that no C is in A.
class C { // Nested class
public:
int i = 0;
};
};
是否有另一种使用模板的方式,即嵌套 class 的整个定义完全包含在父 class 定义中?
简而言之:不,你不能这样做。 您可以在 SO 上找到一些类似的问题,但这一切都归结为能够前向声明嵌套类,没有定义就无法做到这一点。 例如看这个问题。
换句话说,只要挥手,你可能会认为你可以做这样的事情:
class A;
class A::C; // Error: not real C++
class A : public shared_class<A::C> { // Error: incomplete base class
class C {
public:
int i = 0;
};
};
但你不能。 您需要将C
的声明分开,如果要将其用作基类,则需要对其进行定义。 另请参阅此类问题。
如果只是你最关心的命名空间封装,你总是可以只使用一个专用的namespace
,这就是它们的用途。
据我所知,您给出的要求没有针对您的具体案例的解决方案。
直接使用C
作为模板参数不能以任何方式工作,仅仅是因为那时编译器还没有看到C
被声明为A
的成员类,并且因为在该点之前没有办法声明嵌套类.
它不适用于您的特定情况,但有一些限制,您可以通过特征模板或直接通过别名声明向shared_class
模板参数的类型添加间接,这将允许您延迟确定T
是在定义A
之前应该是C
并将C
保持为嵌套类。
不幸的是,如果您想在将使用类模板专业化实例化的声明之一中使用shared_class
的类型T
,这不起作用,这里是shared_ptr<T> d
和T* container()
。 后者可以通过声明返回类型auto
来保存,但前者不能。
这个想法是让shared_class
在任何地方使用typename T::shared_class_type
而不是T
。
A
类将被定义为
class A : public shared_class<A> {
public:
class C {
public:
int i = 0;
};
using shared_class_type = C;
};
或者,您可以定义一个template<typename T> struct shared_class_traits;
, 可能具有包含using shared_class_type = typename T::shared_class_type;
的默认实现在using shared_class_type = A::C;
定义之后可能专门针对A
成员,因此shared_class
可以在任何地方使用typename shared_class_traits<T>::shared_class_type
。 这比使用shared_class_type
“保留”所有类的特定成员名称更灵活。
但正如我在上面解释的那样,只要shared_class
在使用类模板特化实例化的上下文中完全使用shared_class_type
,它就不会起作用。 因此,在成员函数体或默认成员初始化程序内部会很好,但在数据成员或成员函数类型中则不行。
正如其他答案指出的那样,这个问题没有直接的解决方案,因为无法转发声明 class C。
为了仍然能够写A::C
我的解决方案是:
namespace {
class C_Anon{
public:
int i = 0;
};
}
template <class T> class shared_class {
protected:
shared_ptr<T> d = make_shared<T>();
T* container() { return d.get(); }
};
// A is the "parent" class.
class A : public shared_class<C_Anon> {
using C = C_Anon; //Allows for writing A::C
};
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.