消除模板函数特化的歧义 - 值与引用
这个问题需要一些背景信息 - 如果您感到不耐烦,请跳过换行符...我有一个 Vector-3,4
和 Matrix -3,4
根据模板专业化定义的库;即,Vector
和 Matrix
在 Matrix.hh
中定义,而非平凡的实现(例如,矩阵乘法、逆矩阵)在 Matrix.cc
中对于 N = {3,4}
具有明确的特化或实例化。
这种方法效果很好。理论上,应用可以实例化一个 Matrix<100>
,但无法对矩阵进行乘法或反转,因为标头中没有可见的实现模板。在 Matrix.cc
中仅实例化 N = {3,4}
最近,我一直在添加健壮方法来补充涉及的任何操作内积 - 包括矩阵乘法、向量的矩阵变换等。大多数 3D 变换(投影/方向)条件相对良好,并且任何微小的精度误差都不是问题,因为共享顶点/边会产生一致的光栅化。
有些运算必须在数值上是稳健的。我对 GPU 在渲染时如何进行点积和矩阵运算无能为力;但我不能让控制/相机参数阻塞在有效的几何体上 - 并且内积因病态消除误差而臭名昭著,因此稳健的方法使用补偿求和、乘积、点积等。
这适用于,比如说,Matrix.hh
中的Vector
内积:
////////////////////////////////////////////////////////////////////////////////
//
// 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
中的实现是并非微不足道。
当为 [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 中有一个用于运算符 *= 的 N = {3,4} 实现。 cc,但它依赖于朴素的内积并且不稳健 - 尽管通常对于 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) 参数的前一个函数。显然我可以命名< code>robust_multiply 作为其他东西,但我对利用类型系统更感兴趣。我觉得我在
或
中遗漏了一些明显的东西。如何强制调用正确的函数?
(对字数感到抱歉 - 我在写作时试图澄清自己的想法)
This question requires a bit of context - if you're feeling impatient, skip past the line break... I have a Vector-3,4
and Matrix-3,4
library defined in terms of template specializations; i.e., Vector<n>
and Matrix<n>
are defined in Matrix.hh
, while non-trivial implementations (e.g., matrix multiplication, matrix inverse) have explicit specializations or instantiations in Matrix.cc
for N = {3,4}
.
This approach has worked well. In theory, an app could instantiate a Matrix<100>
, but couldn't multiply or invert the matrix, as there are no implementation templates visible in the header. Only N = {3,4}
are instantiated in Matrix.cc
Recently, I've been adding robust methods to complement any operation that involves an inner product - including matrix multiplications, matrix transforms of vectors, etc. Most 3D transforms (projections / orientations) are relatively well-conditioned, and any minor precision errors are not a problem since shared vertices / edges yield a consistent rasterization.
There are some operations that must be numerically robust. I can't do anything about how a GPU does dot products and matrix operations when rendering; but I cannot have control / camera parameters choke on valid geometry - and inner products are notorious for pathological cancellation errors, so the robust methods use compensated summation, products, dot products, etc.
This works fine for, say, Vector
inner product in 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> &);
////////////////////////////////////////////////////////////////////////////////
The implementations in Matrix.cc
are not trivial.
I'm in more dubious territory when adding a robust method for [A]<-[A][B]
matrix multiplication; perhaps the naming is not ideal:
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> &);
There is a N = {3,4}
implementation for the operator *=
in Matrix.cc
, but it relies on the naive inner product and is not robust - though typically good enough for GL / visualization. The robust_multiply
functions are also implemented in Matrix.cc
.
Now of course, I want the Matrix
multiplication operator:
template <int n> GL0::Matrix<n>
operator * (GL0::Matrix<n> m0, const GL0::Matrix<n> & m1) {
return (m0 *= m1);
}
Leading me to the problematic definitions:
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);
}
The call to robust_multiply(m0, m1)
is ambiguous. Q: How can I force the LHS argument to be interpreted as a reference, ensuring a call to the previous function that modifies the (m0) argument. Obviously I can name robust_multiply
as something else, but I'm more interested in utilizing the type system. I feel I'm missing something obvious in <utility>
or <functional>
. How do I force a call to the correct function?
(Sorry about the word count - I'm trying to clarify my own thinking as I write)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
您命名
robust_multiply
错误。*=
和*
是根本不同的操作。它们是相关的,但不是相同的操作 - 不同的动词。当你对不同的名词进行相同的操作时,应该使用重载。
如果你这样做了,那么你的问题几乎肯定会消失。合理的重载很容易编写。
在您的情况下,您希望根据其 l/r 值类别在写入或不写入参数之间进行更改。这会导致歧义问题。
我的意思是,您的问题有解决方法 - 例如,使用
std::ref
或指针,或&
、&&
> 和const&
重载——但它们在这里是补丁。在编程中命名它是很困难的。这是一个你应该做的困难的例子。
...
现在你可以做的一件事就是祝福这些论点。
然后覆盖
*=
和*
以获得稳健的包装矩阵。(lhs 必须足够强大才能减少过载计数)。
现在动词已经清楚了,我只是修饰了一下名词。
但这只是一个想法,并没有经过使用测试。
You named
robust_multiply
wrong.*=
and*
are fundamentally different operations. They are related, but not the same operation - different verbs.Overloading should be used when you are doing the same operation on different nouns.
If you do that, then your problems almost certainly evaporate. Sensible overloads are easy to write.
In your case, you want to change between writing to an argument or not based on its l/r value category. That leads to ambiguity problems.
I mean, there are workarounds to your problem -- use
std::ref
or pointers, for example, or&
,&&
andconst&
overloads -- but they are patches here.Naming this in programming is hard. And here is a case were you should do that hard bit.
...
Now one thing you could do is bless the arguments.
then override
*=
and*
for robust wrapped matrices.(have lhs must be robust to keep overload count down).
Now the verb is clear, I just dressed up the nouns.
But this is just an idea, and not use-tested.