消除模板函数特化的歧义——价值与参考
Disambiguate template function specializations - value vs. reference
这个问题需要一些上下文 - 如果你觉得不耐烦,请跳过换行符... 我有 Vector-3,4
和 Matrix-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.cc
中operator *=
的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。
这个问题需要一些上下文 - 如果你觉得不耐烦,请跳过换行符... 我有 Vector-3,4
和 Matrix-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.cc
中operator *=
的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。