如何在C++中自动生成运算符=?
How to auto-generate operator= in C++?
我有以下模板结构:
template<class T> struct S {
T a,b,c,d,e,f,g,h;
};
然后我尝试这样做:
S<double> sDouble;
S<float> sFloat;
sDouble = sFloat; //Compile error here, since sDouble and sFloat have «unrelated» types
我该怎么办?我有很多这样的结构,里面有很多数据成员。我厌倦了为每个结构提供自定义模板化operator=
,只是为了稍后发现我忘记分配一些成员。
附言上面的情况与下面可以编译的代码非常不一致:
template<class T> using V = T;
int main()
{
V<double> vDouble;
V<float> vFloat;
vDouble = vFloat; //Can be compiled
return 0;
}
编译器无法为两种不同类型的隐式生成赋值运算符。您需要显式定义它。例如
template<class T> struct S
{
T a,b,c,d,e,f,g,h;
template <class U>
S<T> & operator =( const S<U> &s )
{
a = T( s.a );
b = T( s.b );
c = T( s.c );
d = T( s.d );
e = T( s.e );
f = T( s.f );
g = T( s.g );
h = T( s.h );
return *this;
}
};
首先,我建议再看看对这些成员进行分组是否更有意义。例如,也许数组有意义:
std::array<T, 8> data;
在这种情况下,只要您可以对成员进行分组,问题就会减少。
如果这不是一条好路,恐怕在静态反射出现在语言中之前,你能做的最好的事情就是[Boost。PFR(以前称为magic_get(,它试图通过一些聪明和一些黑客(咳嗽复制粘贴的结构化绑定尝试(机制来模拟静态反射。对于C++17:
template<typename OtherT>
S<T>& operator=(const S<OtherT>& other) {
auto this_tuple = boost::pfr::structure_tie(*this);
auto other_tuple = boost::pfr::structure_tie(other);
this_tuple = other_tuple;
return *this;
}
请注意,该类必须可用于结构化绑定。
除了这些,你最好的选择可能是要么把它全部写出来,要么利用一些更强大的基于宏的技术,这些技术允许你以这样一种方式声明或调整一个类,使其变得可反射。例如,Boost.Hana和Boost.Fusion都提供这样的设施。权衡是代码将不那么简单,特别是如果您只需要这个功能。
正如其他答案所暗示的那样,可以通过(很多(boost元编程来实现您想要的行为。使用以下问题的答案: C++预处理器:避免成员变量列表的代码重复,遍历结构体和类成员 我拼凑了一些东西,它遍历两个容器的所有可反射成员,并在转换后分配它们。
但是,我不知道这种方法有多健壮,并且可能建议不要在生产代码中使用它。
#include <boost/preprocessor.hpp>
#include <boost/type_traits.hpp>
#include <boost/mpl/range_c.hpp>
#include <boost/mpl/for_each.hpp>
#include <boost/bind.hpp>
#define REM(...) __VA_ARGS__
#define EAT(...)
#define TYPEOF(x) DETAIL_TYPEOF(DETAIL_TYPEOF_PROBE x,)
#define DETAIL_TYPEOF(...) DETAIL_TYPEOF_HEAD(__VA_ARGS__)
#define DETAIL_TYPEOF_HEAD(x, ...) REM x
#define DETAIL_TYPEOF_PROBE(...) (__VA_ARGS__),
#define STRIP(x) EAT x
#define PAIR(x) REM x
template<class M, class T>
struct make_const
{
typedef T type;
};
template<class M, class T>
struct make_const<const M, T>
{
typedef typename boost::add_const<T>::type type;
};
#define REFLECTABLE(...)
static const int fields_n = BOOST_PP_VARIADIC_SIZE(__VA_ARGS__);
friend struct reflector;
template<int N, class Self>
struct field_data {};
BOOST_PP_SEQ_FOR_EACH_I(REFLECT_EACH, data, BOOST_PP_VARIADIC_TO_SEQ(__VA_ARGS__))
#define REFLECT_EACH(r, data, i, x)
PAIR(x);
template<class Self>
struct field_data<i, Self>
{
Self & self;
field_data(Self & self) : self(self) {}
typename make_const<Self, TYPEOF(x)>::type & get()
{
return self.STRIP(x);
}
typename boost::add_const<TYPEOF(x)>::type & get() const
{
return self.STRIP(x);
}
const char * name() const
{
return BOOST_PP_STRINGIZE(STRIP(x));
}
};
struct reflector
{
//Get field_data at index N
template<int N, class T>
static typename T::template field_data<N, T> get_field_data(T& x)
{
return typename T::template field_data<N, T>(x);
}
// Get the number of fields
template<class T>
struct fields
{
static const int n = T::fields_n;
};
};
// Custom code for struct assignment below here
struct dual_field_visitor
{
template<class CA, class CB, class Visitor, class T>
void operator()(CA & ca, CB & cb, Visitor v, T)
{
v(reflector::get_field_data<T::value>(ca), reflector::get_field_data<T::value>(cb));
}
};
template<class CA, class CB, class Visitor>
void dual_visit_each(CA & ca, CB & cb, Visitor v)
{
typedef boost::mpl::range_c<int,0,reflector::fields<CA>::n> range;
boost::mpl::for_each<range>(boost::bind<void>(dual_field_visitor(), boost::ref(ca), boost::ref(cb), v, _1));
}
struct assign_visitor
{
template<class FieldDataA, class FieldDataB>
void operator()(FieldDataA fa, FieldDataB fb)
{
fa.get() = static_cast<std::decay_t<decltype(fa.get())>>(fb.get());
}
};
template<typename T>
struct Container
{
REFLECTABLE
(
(T) a,
(T) b
)
template<typename U>
Container & operator=(const Container<U> & c)
{
dual_visit_each(*this, c, assign_visitor());
return *this;
}
Container & operator=(const Container & c)
{
if(this != & c)
{
dual_visit_each(*this, c, assign_visitor());
}
return *this;
}
};
int main()
{
Container<int> a {1, 2};
Container<float> b {3.0f, 4.0f};
Container<float> c {5.0f, 6.0f};
a = b;
b = c;
return 0;
}
相关文章:
- 查找自动生成键并具有线性内存消耗的小型关联数组
- Qt:更新 QString 时自动生成的代码失败
- 我可以说服自动生成的构造函数将我的 POD 类成员归零吗?
- 在 C++ 中自动生成方法
- 删除了所有自动生成的构造函数/运算符的类仍然可以从函数返回吗
- 在编译时自动生成用于稀疏数组索引的switch语句
- 如何在C++中自动生成运算符=?
- C++自动生成的具有常量和非常量引用的复制构造函数
- 如何使用 boost/operator.hpp 自动生成 == 运算符?
- Qt自动生成的.rc文件无法打开包含文件'windows.h'
- 阅读自动生成的 DOLFIN c++ 库文档
- 修改Mongodb源代码以禁用文档的自动生成"_id"字段
- 移动构造函数是自动生成的,即使成员没有移动构造函数?
- 如何为C++结构自动生成 python 数据解析器
- 通过 qt 对发送方和接收方使用自动生成的 Ui
- 如何使用C 根据当前时间自动生成新的CSV文件
- Qt:自动生成电源点报告或可编辑的pdf报告
- 如何更改日食自动生成的标题注释
- 绕过自动生成的赋值运算符(VS 错误?
- 为结构/类自动生成流运算符