【发布时间】:2021-06-10 09:49:54
【问题描述】:
我想在我的代码中实现一些惰性求值。这是我想做的 sn-p 代表:
#include <Eigen/Dense>
#include <iostream>
template <int N, int M>
struct S {
template <typename T>
S &operator=(const T &src) {
v = src();
return *this;
}
Eigen::Matrix<double, N, M> v;
};
// If I comment this one the code compiles
template <typename Lhs, typename Rhs>
auto operator+(const Lhs &lhs, const Rhs &rhs) {
return [&]() { return lhs() + rhs(); };
}
template <typename Lhs, int N, int M>
auto operator+(const Lhs &lhs, const S<N, M> &s) {
return [&]() { return lhs() + s.v; };
}
template <typename Rhs, int N, int M>
auto operator+(const S<N, M> &s, const Rhs &rhs) {
return [&]() { return s.v + rhs(); };
}
template <int N0, int M0, int N1, int M1>
auto operator+(const S<N0, M0> &s0, const S<N1, M1> &s1) {
return [&]() { return s0.v + s1.v; };
}
int main() {
static constexpr int n = 4;
S<n, n> s0, s1;
S<Eigen::Dynamic, Eigen::Dynamic> s2;
s1.v = 2. * Eigen::Matrix<double, n, n>::Ones();
s2.v = 3. * Eigen::Matrix<double, n, n>::Ones();
s0 = s1 + s2;
std::cout << s0.v << std::endl;
return 0;
}
我遇到了一个编译错误,这与以下事实有关:在实现 s1 + s2 时,选择了 + 运算符的第一个重载(如果我评论它,代码就可以工作)。似乎对于编译器来说,第一个被认为更专业,而根据我的常识,最后一个更专业:第一个接受任何参数,而最后一个只接受与模板类 @987654324 相关的类型@。
对此有何解释?如何修复这个 sn-p 以使其在保持第一个重载的同时工作(这将是“嵌套”表达式的惰性求值所必需的)?
非常感谢!
编辑:从答案和 cmets 中,我现在了解到问题与 sn-p 中 + 运算符的第一个重载与 Eigen 库中 + 运算符的某些重载之间的冲突有关。以下简化的 sn-p 说明:
#include <Eigen/Dense>
#include <iostream>
template <typename Lhs, typename Rhs>
auto operator+(const Lhs &lhs, const Rhs &rhs) {
return [&]() { return lhs() + rhs(); };
}
int main() {
Eigen::Matrix<double, 4, 4> m0, m1, m2;
m2=m0+m1;
return 0;
}
这里,选择了 sn-p 的 + 运算符,而我预计会选择 Eigen 中的一个......这是为什么呢?
【问题讨论】:
-
不受约束的
operator+确实很危险。 -
大概
Eigen::Dynamic是-1或者至少是一个不能被误解为列数的整数 -
@Jarod42 我知道第一个重载会捕获所有内容,因此会“污染”它定义的整个命名空间。但是如此通用,我希望他在这种情况下不会被选中......另外,您是否看到在不定义此类“通用”运算符的情况下进行惰性评估的技巧?
-
@janou195:“在这种情况下” - 哪个情况?
return s0.v + s1.v;或s0 = s1 + s2;? -
requires(requires (lhs() + rhs()))将是很好的第一步。
标签: c++ templates operator-overloading eigen lazy-evaluation