【问题标题】:C++ how to implement templated converting binary operator overloadsC++如何实现模板化转换二元运算符重载
【发布时间】:2021-02-11 02:19:13
【问题描述】:

我正在尝试这样做:

template<class Float>
struct Number {
  Float v;
  Number(Float iv = 0) : v(iv) {}
};

template<class F>
Number<F> operator+(Number<F> const& a, Number<F> const& b) {   
  return {a.v + b.v};
}

int main() {
  Number<float> y = Number<float>(1) + 2.0f;
  std::cout << y.v << "\n";
}

但它不起作用。

main.cpp:15:38: error: invalid operands to binary expression ('Number<float>' and
      'float')
  Number<float> y = Number<float>(1) + 2.0f;
                    ~~~~~~~~~~~~~~~~ ^ ~~~~
main.cpp:10:11: note: candidate template ignored: could not match
      'Number<type-parameter-0-0>' against 'float'
Number<F> operator+(Number<F> const& a, Number<F> const& b) {   
          ^

由于某种原因,这确实有效:

struct Number {
  float v;
  Number(float iv = 0) : v(iv) {}
};

Number operator+(Number const& a, Number const& b) { 
  return {a.v + b.v};
}

int main() {
  Number x = Number(1) + 2.0f;
  std::cout << x.v << "\n";
}

但我希望模板案例能够正常工作。基本上,我正在寻找任何一种解决方法,以使我能够为 Number 实现二进制运算符,这将允许其中一个 args 可以转换为 Number。最好符合 c++14 标准。

编辑:根据下面 Richard 的链接,我想出了这个似乎可以处理多次转换的情况,但不幸的是,每个运算符仍然需要 3 个重载:

template<class T>
struct identity {
  using type = T;
};

template<class T>
using convertible = typename identity<T>::type;

template<class Float>
struct Param {
  Float v;
};

template<class Float>
struct Number {
  Float v;
  Number(Float iv = 0) : v(iv) {}
  Number(Param<Float> iv) : v(iv.v) {}
};

template<class F>
Number<F> operator+(Number<F> const& a, Number<F> const& b) {
  return {a.v + b.v};
}
template<class F>
Number<F> operator+(Number<F> const& a, convertible<Number<F>> const& b) {
  return {a.v + b.v};
}
template<class F>
Number<F> operator+(convertible<Number<F>> const& a, Number<F> const& b) {
  return {a.v + b.v};
}

int main() {
  std::cout << (Number<float>{1} + 2).v << "\n";
  std::cout << (Number<float>{1} + Param<float>{2}).v << "\n";
  std::cout << (Param<float>{1} + Number<float>{2}).v << "\n";
  std::cout << (Number<float>{1} + Number<float>{2}).v << "\n";
  std::cout << (1 + Number<float>{2}).v << "\n";
}

【问题讨论】:

  • 案例(2):非模板函数将尝试转换以匹配参数类型,Number 具有来自float 的转换构造函数。情况 (1) 模板化函数不会尝试转换 - 在更复杂的情况下,当多个可能的转换可用时,参数应该是什么类型。另外对于情况(2)尝试制作构造函数explicit
  • @RichardCritten 是的,我想这个标准通常是有意义的。但通常 c++ 的限制有解决方法,所以我希望有人能提供帮助。在这种特定情况下,正确的转换总是由其中一个 args 到二进制 op 恰好是 Number.
  • 此处的示例(不需要 C++ 20 - 请参阅下面的答案 - 但您必须创建一些帮助模板)en.cppreference.com/w/cpp/language/… 具体定义 good(x, 1.2)
  • 这似乎会导致其他问题......我也在尝试添加一个向量,它通过 decltype(Vec1()[0] + Vec2( )[0]) 但 operator+ 不搜索转换重载并且替换失败。

标签: c++ type-conversion operator-overloading


【解决方案1】:

template argument deduction 不会考虑隐式转换。

类型推导不考虑隐式转换(除了上面列出的类型调整):这是overload resolution 的工作,稍后会发生。

所以Number(1) + 2.0f中的第二个函数参数b对模板参数F的推导失败,从floatNumber&lt;float&gt;的隐式转换将不予考虑。

你可以添加另外两个重载

template<class F, class V>
Number<F> operator+(Number<F> const& a, V const& b) {   
  return {a.v + Number{b}.v};
}

template<class F, class V>
Number<F> operator+(V const& a, Number<F> const& b) {   
  return {Number{a}.v + b.v};
}

LIVE

【讨论】:

  • 如果我想支持定义了 Number(X &) 的第二种类型 X,那么我是否必须编写 4 个版本的 + 运算符?或者有没有更优雅的方法来识别第二个参数可以转换为数字,但不会对数字+数字产生歧义
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-04-28
  • 2010-11-01
  • 1970-01-01
  • 2012-03-24
  • 1970-01-01
相关资源
最近更新 更多