Create a family of template classes convertible to each other

╄→гoц情女王★ 提交于 2019-12-24 14:58:05

问题


I want to create a family of template classes, where each of them would derive from common base. This common base would define, how to convert instance of one of these derived classes to any other. I have created base class template with both copy constructor and copy assignment operator, here is the code:

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

Then, I created 2 derived classes, which derive from this base class, so that I can avoid to duplicate code for copy construction and copy assignment for each possible combination of derived classes:

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

Here is my test code:

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

When it comes to copy assignment, everything works as intended, however when I uncomment line where I try to initialize new object of type class_2 with object of type class_1, compiler complains with following error:

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

Shouldn't compiler see inherited copy constructor from base class? Is there some workaround to avoid duplicating copy constructor for every single class belonging to class_family?


回答1:


Shorter reproduction:

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

E e{D{}}; // error

Basically, copy and move constructors are never inherited - those are specifically excluded from consideration as candidates. You'd have to explicitly add those extra candidates if you want them.

From [over.match.funcs]/8:

A constructor inherited from class type C ([class.inhctor.init]) that has a first parameter of type “reference to cv1 P” (including such a constructor instantiated from a template) is excluded from the set of candidate functions when constructing an object of type cv2 D if the argument list has exactly one argument and C is reference-related to P and P is reference-related to D. [ Example:

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

— end example ]


This is CWG 2356 and also CWG 1959 (which was also partially resolved by P0136).



来源:https://stackoverflow.com/questions/55442423/create-a-family-of-template-classes-convertible-to-each-other

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!