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

How can I structure common data while retaining defaulted move ctor and assignment?

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

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 需要访问 base 中的元素 data,所以我想将这些基数做成模板化的 class,这样它们的函数就可以访问 data。此外,这些基础实际上有时是模板化的,因此我也需要添加此功能。我到目前为止是这样的:

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>;

但是,我敢肯定其中有很多错误。我现在在 GCC 4.9 中得到的编译器错误是(当仅使用 derived2 时)是模板参数 1 在 class 派生中无效。

尽管评论中提出了有效论点,但我还是设法创建了模板。这是为了防止其他人需要计算模板部分:

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>;