创建可相互转换的模板类系列

Create a family of template classes convertible to each other

本文关键字:系列 转换 创建      更新时间:2023-10-16

我想创建一个模板类系列,其中每个模板类都来自公共基础。这个公共基础将定义如何将其中一个派生类的实例转换为任何其他实例。我已经创建了带有复制构造函数和复制赋值运算符的基类模板,这是代码:

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_1类型的对象初始化类型class_2的新对象,编译器抱怨以下错误:

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

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

较短的复制:

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]) 继承的构造函数,其第一个参数类型为"引用cv1P"(包括从模板实例化的此类构造函数)在构造cv2类型的对象时D如果参数列表只有一个参数并且CP引用相关,并且PD引用相关。[示例:

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

结束示例]


这是CWG 2356,也是CWG 1959(P0136也部分解决了这个问题)。