首页 > 解决方案 > 创建一系列可相互转换的模板类

问题描述

我想创建一个模板类家族,其中每个模板类都派生自公共基础。这个公共基础将定义如何将这些派生类之一的实例转换为任何其他类。我用复制构造函数和复制赋值运算符创建了基类模板,代码如下:

template < class T >
struct class_family
{
    T data;
    class_family() = default;
    class_family(const class_family& a) : data(a.data) { }
    class_family& operator=(const class_family& a) { data = a.data; return *this; };
};

然后,我创建了 2 个派生类,它们派生自这个基类,这样我就可以避免为每个可能的派生类组合重复复制构造和复制赋值的代码:

template < class T >
struct class_1
    : public class_family< T >
{
    using class_family< T >::class_family;
    using class_family< T >::operator=;
};

template < class T >
struct class_2
    : public class_family< T >
{
    using class_family< T >::class_family;
    using class_family< T >::operator=;
};

这是我的测试代码:

int main(int argc, char** argv)
{
    class_1<int> c1;
    class_2<int> c2;
    c1 = c2;
    // class_2<int> c3 = c1;
}

当涉及到复制分配时,一切都按预期工作,但是当我取消注释我尝试使用类型对象初始化新类型class_2对象的行时class_1,编译器会抱怨以下错误:

E0312   no suitable user-defined conversion from "class_1<int>" to "class_2<int>" exists

编译器不应该看到从基类继承的复制构造函数吗?是否有一些解决方法可以避免为属于的每个类重复复制构造函数class_family

标签: c++c++17

解决方案


更短的复制:

struct B { };
struct D : B { using B::B; };
struct E : B { using B::B; };

E e{D{}}; // error

基本上,复制和移动构造函数永远不会被继承——它们被明确排除在候选对象之外。如果需要,您必须明确添加这些额外的候选人。

来自[over.match.funcs]/8

从类类型C([class.inhctor.init]) 继承的具有类型“对cv1 P的引用”的第一个参数的构造函数(包括从模板实例化的这种构造函数)在构造对象时从候选函数集中排除如果参数列表只有一个参数并且与引用相关并且与引用相关,则键入cv2 。[ <em>例子:DCPPD

struct A {
  A();
  A(A &&);                              // #1
  template<typename T> A(T &&);         // #2
};
struct B : A {
  using A::A;
  B(const B &);                         // #3
  B(B &&) = default;                    // #4, implicitly deleted

  struct X { X(X &&) = delete; } x;
};
extern B b1;
B b2 = static_cast<B&&>(b1);            // calls #3: #1, #2, and #4 are not viable
struct C { operator B&&(); };
B b3 = C();                             // calls #3

— <em>结束示例]


这是CWG 2356CWG 1959(也由P0136部分解决)。


推荐阅读