【问题标题】:C++: wrong template function overload selectionC++:错误的模板函数重载选择
【发布时间】: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


【解决方案1】:

似乎选择了第一个重载,但不是s1 + s2。即选择第 4 个重载。但是,在第 4 个重载中,您有 s0.v + s1.v;,而 .v 不是 S&lt;N, M&gt;

【讨论】:

  • 我不明白你的回答。 '选择第一个重载,但不是 s1 + s2' 是什么意思?另外我不确定你在第二句话中的意思......
  • @janou195:您正确地注意到在上面的代码中选择了第一个重载,因为删除它会有所不同。您错误地假设它是为s0 = s1 + s2; 行选择的。该行反而实例化了第 4 个重载。反过来,实例化包含s0.v + s1.v;再次需要operator+ 的重载分辨率。 现在是否注释掉第一个重载很重要。
  • 谢谢,我明白了!我的解释是错误的。但现在我的问题是:为什么在s0.v + s1.v 现场选择了我的运算符而不是 Eigen 运算符?我会在这个意义上编辑我的问题!
猜你喜欢
  • 2019-04-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多