繁体   English   中英

使用嵌套的 class 作为父 class 模板参数?

[英]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> dT* 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM