问题描述
是否可以避免为下面的结构 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
基本模板类,并为类A
和B
从其继承。
但是,拷贝赋值运算符是一种特殊的成员函数,我认为不能在基类中返回用于不同类型的模板。因此,您需要为每个班级提供课程。
意思是,你可以做
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
};
但是,A
,B
这两个结构似乎仅与两个成员不同(即C0
,C1
和D0
,{{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。