为两个类似的类定义一次成员函数?

问题描述

是否可以避免为下面的结构 A,B 定义两次相同的功能?它们的成员命名完全相同,但是 v0,v1 ... vN 成员在两个结构 A B 之间具有不同的类型。 。如果有帮助,成员 v *都来自同一结构 V

非平凡的函数(即Assignment =)可以在结构外部重用模板化的复制函数,如下所示,但是如果将其一次定义在结构中,则将是首选/更简洁的方法

是否有一种干净的方法可以将 A B 的定义模板化为一个

template <class T1,class T2>
void copy(T1& to,T2& from)
{
    to.v0 = from.v0;
    to.v1 = from.v1;
    to.type = from.type;
}

enum class E { TYPE_0,TYPE_1 };

struct B;

struct A 
{
    C0<float> v0;
    C1<int> v1;
    E type;

    A& operator = (const B& t)
    {
        copy(*this,t);
        return *this;
    } 
    
    string strType() { return string(type); }    
};

struct B
{
    D0<float> v0;
    D1<int> v1;
    E type;

    B& operator = (const A& t)
    {
        copy(*this,t);
        return *this;
    } 

    string strType() { return string(type); }
}

解决方法

您可以为通用功能保留common基本模板类,并为类AB从其继承。

但是,拷贝赋值运算符是一种特殊的成员函数,我认为不能在基类中返回用于不同类型的模板。因此,您需要为每个班级提供课程。

意思是,你可以做

enum class E { TYPE_0,TYPE_1 };
struct B;

template<typename ClassA,typename ClassB> struct Common
{
   template<E type> 
   std::string strType() { return std::to_string(static_cast<int>(type)); }
   // need to cast the type to int before you convert std::to_string

   // other common-member-functions
};

struct A : public Common<A,B>
{
   C0 v0;
   C1 v1;
   E type;
   // ... A& operator = (const B& t)
   // bring the common functionalities to A
   using Common<A,B>::strType;
   // ... other member-functions
};

struct B : public Common<B,A>
{
   D0 v0;
   D1 v1;
   E type;
   // ... B& operator = (const A& t)
   // bring the common functionalities to A
   using Common<B,A>::strType;
   // ... other member-functions
};

但是,AB这两个结构似乎仅与两个成员不同(即C0C1D0,{{1 }}),通过制作class-template将两个类组合为一个类,这也是一种选择:

以下是示例代码:

D1
,

这恰好是称为CRTP(奇怪地重复使用的模板模式)的模式的用例。

想法是定义一个基类模板,该基类将派生类作为模板参数。然后,您可以安全地将基类中的this强制转换为派生类,并访问基类中的派生类成员。

这也适用于副本分配运算符。

#include <string>
#include <iostream>

template<typename Derived>
struct CRTPBase {
    
    Derived& self() { return static_cast<Derived&>(*this); }
    const Derived& self() const { return static_cast<const Derived&>(*this); }

    std::string strType() { return self().type;}

    template<class OtherDerived>
    Derived& operator=(const CRTPBase<OtherDerived>& other) {
        self().type = other.self().type;
        return self();
    }
};

struct A : public CRTPBase<A>
{
   using Base = CRTPBase<A>;
   std::string type = "A";

   using Base::operator=;
};

struct B :  public CRTPBase<B>
{
      using Base = CRTPBase<B>;
   std::string type = "B";

   using Base::operator=;
};

int main() {

    A a;
    B b;
    std::cout << a.strType() << std::endl; // Prints: A
    std::cout << b.strType() << std::endl; // Prints: B
    
    a = b;
    
    std::cout << a.strType() << std::endl; // Now prints: B
}

实时示例here