请考虑以下事项:
template <class T>
struct C {
T a, b, c;
};
struct CSnapshot : public C<float> {};
struct CRealtime : public C<const float*> {
CRealtime() {
// Pointers are bound to some mutable data
}
void snapshotInto(CSnapshot& snapshot) {
snapshot.a = *a;
snapshot.b = *b;
snapshot.c = *c;
}
};
有没有什么好方法可以使snapshotInto
方法在DRYer之上?因此,例如,如果添加d
,则无法选择忘记在snapshotInto
方法中对其状态进行快照,或者意外将实时c
值快照到其中。
动机:可能需要这种代码,例如,如果您有一个使用某些参数的音频呈现线程,这些参数可能会因用户交互而在不同的线程上发生变化。要使用音频渲染线程中的参数,您需要确保参数值不会在您的脚下发生变化,因此您每次调用渲染回调时都会在渲染回调的开头创建实时变量的快照。
P.S。我不是坚持上面的实现;例如,如果你将实时指针和快照值放入结构中,那么有一种DRY方式可以正常工作,例如,这很好; 然而,仍然应该有一种方法来获得类似于CSnapshot
对象的接口,因此给定一个对象snapshot
,用户只需编写snapshot.a
获取快照浮点值,并且不必写入例如snapshot.a.getVal()
。
P.P.S。性能至关重要,因此必须按键访问地图,例如,获取快照值或实时指针,不会这样做。
答案 0 :(得分:1)
您正在寻找某种静态反射,这在C ++中不可用(尚)。这是一个使用BOOST_HANA_DEFINE_STRUCT
的解决方案:
template <typename T>
struct C {
BOOST_HANA_DEFINE_STRUCT(C,
(T, a),
(T, b),
(T, c)
);
};
struct CSnapshot : public C<float> {};
struct CRealtime : public C<const float*>
{
void snapshotInto(CSnapshot& snapshot)
{
constexpr auto snapshot_accessors = boost::hana::accessors<CSnapshot>();
constexpr auto realtime_accessors = boost::hana::accessors<CRealtime>();
constexpr auto range = boost::hana::make_range(
boost::hana::int_c<0>, boost::hana::size(realtime_accessors));
boost::hana::for_each(range, [&](auto i)
{
auto snapshot_getter = boost::hana::second(snapshot_accessors[i]);
auto realtime_getter = boost::hana::second(realtime_accessors[i]);
snapshot_getter(snapshot) = *(realtime_getter(*this));
});
}
};
用法:
int main()
{
float a=1, b=2, c=3;
CSnapshot cs;
CRealtime cr{{&a, &b, &c}};
cr.snapshotInto(cs);
assert(cs.a == a);
assert(cs.b == b);
assert(cs.c == c);
}
上面的示例使用-Ofast -fno-exceptions -fno-rtti
在Win x64上使用 g ++ 7.0.0 20160825 编译为以下程序集:
main:
subq $40, %rsp
call __main
xorl %eax, %eax
addq $40, %rsp
ret