如何在保留默认移动ctor和赋值的同时构建公共数据?

时间:2015-10-09 03:44:22

标签: c++ c++11 template-meta-programming

我有几个共享共同点的类:它们的构造方式和它们所拥有的数据。但是,每个人都有一个独特的dtor。因此,尝试删除代码重复并使它们从基类继承似乎是显而易见的。所以我从这开始:

class base{
protected:
    int data;
public:
    base() = default;
    base(const base &) = delete;
    base& operator=(const base &) = delete;
    base(base &&) = default;
    base& operator=(base &&) = default;
};

class derived: public base{
public:
    ~derived() {}
};

然而,出现了问题。我不能这样做

derived d;
derived e(std::move(d));

原因是因为derived声明了一个dtor,这意味着不会生成移动ctor / assignment。所以我的下一个想法是颠倒继承,我想出了这个。因为我(在我的原始例子中)有多个派生和单个基础,我想这样做的方式是有多个基础和一个派生,这将被模板化指向不同的基础。

class base1{
public:
    ~base1() {}
};

class base2{
public:
    ~base2() {}
};

template<class T>
class derived: public T{
protected:
    int data;
public:
    derived() = default;
    derived(const derived &) = delete;
    derived& operator=(const derived &) = delete;
    derived(derived &&) = default;
    derived& operator=(derived &&) = default;
};

using derived1 = derived<base1>;
using derived2 = derived<base2>;

这一切都很好,花花公子,它编译! 但是,base1base2需要访问data中的元素base,因此我认为将基数设为模板类,以便其函数可以访问{{1 }}。此外,基本实际上有时是模板化的,所以我也需要添加这个功能。到目前为止我所拥有的是:

data

但是,我确信有很多错误。我现在在GCC 4.9中得到的编译器错误是(当只使用template<class T1, class T2> class base1{ public: ~base1() { std::cout<<T1::data; } }; template<class T> class base2{ public: ~base2() { std::cout<<T::data; } }; template<template <class, class...> class T, class... Ts> class derived: public T<typename derived, Ts...>{ protected: int data; public: derived() = default; derived(const derived &) = delete; derived& operator=(const derived &) = delete; derived(derived &&) = default; derived& operator=(derived &&) = default; }; using derived1int = derived<base1<int>>; using derived1float = derived<base1<float>>; using derived2 = derived<base2>; 时)模板参数1在派生类中无效。

1 个答案:

答案 0 :(得分:0)

虽然评论中有有效的参数,但我设法创建了模板。在这里,万一其他人需要解决模板部分:

template<class T1, class Data>
class base1{
public:
    ~base1() {
        std::cout<<static_cast<T1*>(this)->data << " " <<typeid(std::declval<Data>()).name();
    }
};

template<class T>
class base2{
public:
    ~base2() {
        std::cout<< static_cast<T*>(this)->data;
    }
};

template<template <class, class...> class T, class ... Ts >
class derived: public T< derived<T, Ts...>, Ts...>{
    friend class T<derived<T, Ts...>, Ts...>;
    int data = 0;
public:
    derived() = default;
    derived(const derived &) = delete;
    derived& operator=(const derived &) = delete;
    derived(derived && d){
        std::swap(data, d.data);
    }
    derived& operator=(derived && d){
        std::swap(data, d.data);
        return *this;
    }
};

using derived1int = derived<base1, int>;
using derived1float = derived<base1, float>;
using derived2 = derived<base2>;