[英]Define member functions once for two similar classes?
是否可以避免为下面的结构A、B定义相同的函数两次? 它们的成员命名完全相同,但v0, v1 ... vN成员在两个结构A和B之间属于不同类型。 如果它有帮助,成员v * 都来自同一个结构V 。
非平凡的函数(即赋值 =)可以在结构之外重用模板化的复制函数,如下所示,但如果在结构内定义一次,它会是首选/更干净的。
有没有一种干净的方法可以将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
、 D1
),通过创建类模板将两个类合并为一个,也是一种替代方法:
下面是一个示例代码:
#include <iostream>
#include <vector>
#include <string>
enum class E { TYPE_0, TYPE_1 };
template<typename T1, typename T2>
struct AandB
{
T1 v0;
T2 v1;
E type;
AandB() : type{ E::TYPE_0 } {}
AandB& operator= (const AandB& rhs) // one operator =
{
v0 = rhs.v0;
v1 = rhs.v1;
type = rhs.type;
return *this;
}
std::string strType() const { return std::to_string(static_cast<int>(type)); }
};
int main()
{
using C0 = std::vector<float>;
using C1 = std::vector<int>;
AandB<C0, C1> obj;
std::cout << obj.strType() ; // Prints: 0
}
这正是称为 CRTP(Curious Recurring Template Pattern)的模式的用例。
这个想法是定义一个基类模板,将派生类作为模板参数。 然后您可以安全地将基类中的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
}
现场示例在这里。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.