C ++编译子向量和成员的时间解释

时间:2017-07-18 05:48:14

标签: c++ c++11 armadillo rvalue

我有一个粒子类可以保持物体的位置,速度和加速度。我可以通过.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

Armadillo documentation

1 个答案:

答案 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)
}

那应该是它。