消除模板函数特化的歧义——价值与参考

Disambiguate template function specializations - value vs. reference

这个问题需要一些上下文 - 如果你觉得不耐烦,请跳过换行符... 我有 Vector-3,4Matrix-3,4 根据模板特化定义的库;即,Vector<n>Matrix<n>Matrix.hh 中定义,而 non-trivial 实现(例如,矩阵乘法、矩阵求逆)在 Matrix.cc 中具有明确的特化或实例化N = {3,4}.

这种方法效果很好。理论上,应用程序可以实例化 Matrix<100>,但不能乘以或反转矩阵,因为 header 中没有可见的实现模板。在Matrix.cc

中只实例化了N = {3,4}

最近,我一直在添加 robust 方法来补充涉及内积的任何操作 - 包括矩阵乘法、向量矩阵变换等。大多数 3D 变换(投影/ 方向)相对 well-conditioned,任何微小的精度误差都不是问题,因为共享的顶点/边会产生一致的光栅化。

有一些操作必须在数值上稳健。我对 GPU 在渲染时如何进行点积和矩阵运算无能为力;但我 不能 控制/相机参数在有效几何体上阻塞 - 并且内积因病态消除错误而臭名昭著,因此稳健的方法使用补偿求和、乘积、点积等。



这适用于 Vector Matrix.hh 中的内积:

////////////////////////////////////////////////////////////////////////////////
//
// inner product:


template <int n> float
inner (const GL0::Vector<n> & v0, const GL0::Vector<n> & v1)
{
    float r = v0[0] * v1[0];

    for (int i = 1; i < n; i++)
        r += v0[i] * v1[i];

    return r; // the running sum for the inner product.
}


float
robust_inner (const GL0::Vector<3> &, const GL0::Vector<3> &);

float
robust_inner (const GL0::Vector<4> &, const GL0::Vector<4> &);


////////////////////////////////////////////////////////////////////////////////

Matrix.cc 中的实现是 not trivial

在为 [A]<-[A][B] 矩阵乘法添加稳健的方法时,我处于更加可疑的领域;也许命名不理想:

template <int n> GL0::Matrix<n> &
operator *= (GL0::Matrix<n> & m0, const GL0::Matrix<n> & m1);

// (external instantiation)


GL0::Matrix<3> &
robust_multiply (GL0::Matrix<3> &, const GL0::Matrix<3> &);

GL0::Matrix<4> &
robust_multiply (GL0::Matrix<4> &, const GL0::Matrix<4> &);

Matrix.ccoperator *=N = {3,4}实现,但它依赖于朴素的内积并且不稳健- 虽然通常足以用于 GL / 可视化。 robust_multiply 功能也在 Matrix.cc 中实现。

当然,我想要 Matrix 乘法运算符:

template <int n> GL0::Matrix<n>
operator * (GL0::Matrix<n> m0, const GL0::Matrix<n> & m1) {
    return (m0 *= m1);
}

让我想到有问题的定义:

inline GL0::Matrix<3>
robust_multiply (GL0::Matrix<3> m0, const GL0::Matrix<3> & m1) {
    return robust_multiply(m0, m1);
}

inline GL0::Matrix<4>
robust_multiply (GL0::Matrix<4> m0, const GL0::Matrix<4> & m1) {
    return robust_multiply(m0, m1);
}

robust_multiply(m0, m1) 的调用 不明确 问:如何强制将 LHS 参数解释为引用,确保调用修改 (m0) 参数的前一个函数。 显然我可以将 robust_multiply 命名为其他名称,但我对使用类型系统更感兴趣。我觉得我在 <utility><functional> 中遗漏了一些明显的东西。如何强制调用正确的函数?


(抱歉字数问题 - 我在写的时候试图理清自己的想法)

你命名 robust_multiply 错误。

*=* 是根本不同的操作。它们是相关的,但不是相同的操作 - 不同的动词。

当你对不同的名词做相同的操作时,应该使用重载。

如果你这样做,那么你的问题几乎肯定会烟消云散。合理的重载很容易编写。

在您的情况下,您希望根据其 l/r 值类别在写入参数或不写入参数之间进行更改。这会导致歧义问题。

我的意思是,您的问题有变通方法——例如,使用 std::ref 或指针,或者 &&&const& 重载——但是它们是这里的补丁。

在编程中命名这个很难。在这种情况下,您应该努力做到这一点。

...

现在你可以做的一件事就是祝福论点。

template<class T>
struct robust{
  T t;
  explicit operator T&()&{return t;}
  explicit operator T()&&{
    return std::forward<T>(t);
  }
  // also get() methods
  explicit robust(T&&tin):
    t(std::forward<T>(tin))
  {}
};

然后覆盖 *=* 以获得稳健的包装矩阵。

robust{a}*=b;

(lhs 必须稳健以减少过载计数)。

现在动词清楚了,我只是把名词装扮了一下。

但这只是一个想法,而不是use-tested。