自己实现 Clip()

Implement Clip() in Eigen

我有一些代码可以将一些值裁剪到以 0 为中心的范围内,如下所示。

Eigen::VectorXd a;
Eigen::VecotrXd b;
a = a.cwiseMin(b).cwiseMax(-b);  // no temporary created here?

我想将逻辑分解成一个函数。 一种解决方案:

Eigen::VectorXd Clip(const Eigen::VectorXd& a, const Eigen::VectorXd& b);

a = Clip(a, b);

但我认为这是低效的,因为它创建了一个额外的临时文件?

另一个解决方案:

void Clip(Eigen::Ref<Eigen::VectorXd> a, const Eigen::VectorXd& b) {
  a = a.cwiseMin(b).cwiseMax(-b);
}

不过这个有时候用起来好像不太方便:

void SomeFunctionSignatureICannotChange(const Eigen::VectorXd& a, const Eigen::VectorXd& b) {
  // Eigen::VectorXd a_clipped = Clip(a, b); would be cleaner.
  Eigen::VectorXd a_clipped;
  Clip(a_clipped, b);
}

我能想到的最佳方案:

template <typename DerivedV, typename DerivedB>
auto Clip(const Eigen::ArrayBase<DerivedV>& v,
          const Eigen::ArrayBase<DerivedB>& bound)
          -> decltype(v.min(bound).max(-bound)) {
  return v.min(bound).max(-bound);
}

(我假设 'auto' 在这种情况下是好的,而不是 common pitfalls 警告过的那个?)

不过代码好像template-heavy又一个bit-complicated。例如,google 样式指南 here:

不鼓励尾随 return 类型

Use the new trailing-return-type form only in cases where it's required (such as lambdas) or where, by putting the type after the function's parameter list, it allows you to write the type in a much more readable way. The latter case should be rare; it's mostly an issue in fairly complicated template code, which is discouraged in most cases.

或者,如果我删除尾随的 return 类型,函数 return 类型推导将开始。但是 google 风格指南似乎也不鼓励函数 return 类型扣除 public headers here

Furthermore, use it only if the function or lambda has a very narrow scope, because functions with deduced return types don't define abstraction boundaries: the implementation is the interface. In particular, public functions in header files should almost never have deduced return types.

我是 Eigen 和 C++ 的新手,所以不确定我是否遗漏了什么。希望吸取大家的意见和建议。谢谢!

我确认 a = a.cwiseMin(b).cwiseMax(-b); 没有创建任何临时文件。在您的情况下,强烈建议使用 auto return 类型,我还认为您的用例是上述规则的完全合法例外:

  • 显式编写 return 类型将是一场噩梦并且容易出错。
  • 这是一个非常短的函数,预计会被内联。因此,它应该同时被声明和定义。因此第二条规则并不适用。

在 c++14 中你甚至可以省略冗余:

template <typename DerivedV, typename DerivedB>
auto Clip(const Eigen::ArrayBase<DerivedV>& v,
          const Eigen::ArrayBase<DerivedB>& bound)
{
  return v.min(bound).max(-bound);
}