我有一个粒子类可以保持物体的位置,速度和加速度。我可以通过.position()
,.velocity()
和.acceleration()
访问向量的相关部分。我也可以访问每个单独的号码,例如.velocity_x()
,.velocity_y()
,.velocity_z()
等。我想要做的是以这种方式访问速度的z部分:
p.velocity().z()
我想同时使用.velocity()
(作为子向量)和.velocity().z()
(作为单个数字)。
我也想避免定义任何额外的变量。我更喜欢在编译时解释所有内容(由于性能优先)。
这个实现在c ++中是否可行?
在尝试中,我考虑过使用仿函数返回另一个类。但除了编译时解释问题之外,const
存在一个问题,因为.velocity()
不知道它是否会跟const
或非const
形式{ {1}}。
.z()
请:
#include <iostream>
#include <armadillo>
class Particle
{
public:
arma::vec::fixed<9> data;
inline double velocity_z() const
{
return data(5);
}
inline double& velocity_z()
{
return data(5);
}
inline const arma::subview_col<double> position() const
{
return data.subvec(0,2);
}
inline arma::subview_col<double> position()
{
return data.subvec(0,2);
}
inline const arma::subview_col<double> velocity() const
{
return data.subvec(3,5);
}
inline arma::subview_col<double> velocity()
{
return data.subvec(3,5);
}
inline const arma::subview_col<double> acceleration() const
{
return data.subvec(6,8);
}
inline arma::subview_col<double> acceleration()
{
return data.subvec(6,8);
}
};
arma::vec vector3(double x,double y,double z)
{
return {x,y,z};
}
int main()
{
Particle p;
p.position()=vector3(1.1,2.1,3.1);
p.velocity()=vector3(1.2,2.2,3.2);
p.velocity_z()=10.0;
p.acceleration()=vector3(1.3,2.3,3.3);
p.data.print();
return 0;
}
// output:
// 1.1000
// 2.1000
// 3.1000
// 1.2000
// 2.2000
// 10.0000
// 1.3000
// 2.3000
// 3.3000
答案 0 :(得分:2)
嗯,一个可能的解决方案是返回一个代理对象,它既暴露.{x|y|z}()
成员函数,又可以隐式转换为向量类型。
概念上是这样的:
#include <type_traits>
using vector_t = /* your library type */;
template<bool RValue>
class vector_proxy {
using return_type = typename std::conditional<RValue, vector_t&&, vector_t const&>::type;
vector_t &ref;
public:
vector_proxy(vector_t &ref) : ref(ref) {}
vector_proxy(vector_proxy const&) = delete;
vector_proxy& operator=(vector_proxy const&) = delete;
vector_proxy(vector_proxy&&) = delete;
vector_proxy& operator=(vector_proxy&&) = delete;
auto x() { /* code to produce x */ }
auto y() { /* code to produce y */ }
auto z() { /* code to produce z */ }
operator return_type() { return static_cast<return_type>(ref); }
};
为什么要模板?因为我会想象你想要不同的行为,这取决于粒子对象的值类别。
如果粒子是左值,我们不希望返回粒子内部数据的非const引用。如果它是一个右值,我们也可以返回一个右值引用,这样代码的行为就像预期的那样&#34;。
粒子的成员函数velocity()
可以具有值类别限定符以区分这两种情况。上面的模板只捕获常见行为并抽象出差异。
class particle {
// Members
public:
vector_proxy<false> velocity() const& { return {/* A ref to the velocity member */}; }
vector_proxy<true> velocity() && { return {/* A ref to the velocity member */}; }
// More functionality
};
因为你在评论中澄清了velocity
总是shuold按值返回一个新的矢量对象(一个很好的默认方法,顺便说一句),同时也允许修改粒子。上述解决方案需要更新:
class particle;
template<bool ByRef>
class vector_proxy {
using return_type =
typename std::conditional<ByRef, double&, double>::type;
using ref_type =
typename std::conditional<ByRef, particle&, particle const&>::type;
ref_type ref;
public:
vector_proxy(ref_type ref) : ref(ref) {}
vector_proxy(vector_proxy const&) = delete;
vector_proxy& operator=(vector_proxy const&) = delete;
vector_proxy(vector_proxy&&) = delete;
vector_proxy& operator=(vector_proxy&&) = delete;
return_type x();
return_type y();
return_type z();
operator vector_t();
};
class particle {
// Members
template<bool>
friend class vector_proxy;
public:
vector_proxy<false> velocity() const { return {*this}; }
vector_proxy<true> velocity() { return {*this}; }
// More functionality
};
template<bool ByRef>
auto vector_proxy<ByRef>::x -> return_type {
return ref.data(3);
}
template<bool ByRef>
auto vector_proxy<ByRef>::y -> return_type {
return ref.data(4);
}
template<bool ByRef>
auto vector_proxy<ByRef>::z -> return_type {
return ref.data(5);
}
template<bool ByRef>
vector_proxy<ByRef>::operator vector_t() {
return ref.data.subvec(3, 5)
}
那应该是它。