[英]How do you resolve ambiguity between template operators?
I've looked far and wide and everyone seems to have a slightly different issue than me.我已经看得很远了,每个人似乎都有与我略有不同的问题。
For simplicity say I have a template struct Complex<X>
and I want it to have overloads for real values and at least other Complex.为简单起见,假设我有一个模板结构
Complex<X>
,并且我希望它具有实际值的重载,至少还有其他 Complex。 As a rule, operations between double
or Complex<double>
and Complex<float>
(on either side) should return Complex<double>
.通常,
double
或Complex<double>
与Complex<float>
(在任一侧)之间的操作应返回Complex<double>
。 I'm currently using deduction guides that work quite well for this, but other options are std::common_type_t<X,Y>
, decltype(std::declval<X>()+std::declval<Y>())
, etc.我目前正在使用对此非常有效的演绎指南,但其他选项是
std::common_type_t<X,Y>
, decltype(std::declval<X>()+std::declval<Y>())
, ETC。
(1) `auto operator+(X const&)`
(2) `friend auto operator+(X const&, Complex<X> const&)`
(2) `template<class Y> auto operator+(Y const&)`
(3) `template<class Y> auto operator+(Complex<Y> const&)`
(4) `template<class Y> friend auto operator+(Y const&, Complex<X> const&)`
Here's the problem.这就是问题所在。 If I write (1-2), then
Complex<float>
sees doubles as floats.如果我写 (1-2),那么
Complex<float>
将双打视为浮点数。 If I make that (2-3), then apparently adding Complex<double>
is ambiguous between (2,3,4).如果我做到了 (2-3),那么在 (2,3,4) 之间添加
Complex<double>
显然是不明确的。 Non-template operators wouldn't be ambiguous, but please assume there are too many template arguments to name.非模板运算符不会有歧义,但请假设有太多模板参数需要命名。
Next I thought that the CV/references were to blame, but making (1-2) operators of X
changed nothing.接下来,我认为应该归咎于 CV/references,但是使 (1-2)
X
的运算符没有任何改变。 This appears to be opposite the behavior of auto x
which won't be a reference.这似乎与
auto x
的行为相反,它不会作为参考。
I tried adding assertions like static_assert(std::is_arithmetic_v<Y>)
to (1-2) but they don't participate.我尝试将诸如
static_assert(std::is_arithmetic_v<Y>)
类的断言添加到 (1-2) 但它们不参与。
After trying static assertions that didn't help from the function body, I thought before I move on I should try enabling/disabling functions another way.在尝试了对函数体没有帮助的静态断言之后,我想在继续之前我应该尝试以另一种方式启用/禁用函数。 I remember this approach not working correctly in the past, so I didn't try it until much too late.
我记得这种方法在过去不能正常工作,所以我没有尝试,直到为时已晚。
template<class Y>
auto operator+(Complex<X> const& x, Complex<Y> const& y)
-> std::enable_if<std::is_arithmetic_v<Y>,
Complex<decltype(std::declval<X>(), std::declval<Y>())>> {/*...*/}
template<class Y>
auto operator+(Complex<X> const& x, Y const& y)
-> std::enable_if<std::is_arithmetic_v<Y>,
Complex<decltype(std::declval<X>(), std::declval<Y>())>> {/*...*/}
template<class Y>
friend auto operator+(Y const& y, Complex<X> const& x)
-> std::enable_if<std::is_arithmetic_v<Y>,
Complex<decltype(y, std::declval<X>())>> {/*...*/}
This isn't the code I'm using, I've paraphrased everything.这不是我正在使用的代码,我已经解释了所有内容。 Please let me know if I made a mistake somewhere.
如果我在某个地方犯了错误,请告诉我。
This table shows the sum type of the row and column correctly.此表正确显示了行和列的总和类型。 If either field type has double precision then so does the result;
如果任一字段类型具有双精度,则结果也是如此; the same goes if either type is complex.
如果任何一种类型都很复杂,情况也是如此。
add f d Complex<f> Complex<d>
f f d Complex<f> Complex<d>
d d d Complex<d> Complex<d>
Complex<f> Complex<f> Complex<d> Complex<f> Complex<d>
Complex<d> Complex<d> Complex<d> Complex<d> Complex<d>
As an aside, if you define assignment operators like operator+=
, then Complex<X>
only goes on the left (no friend functions) and only returns Complex<X>&
(type is fixed.) It should probably accept the same types as operator+
or use operator+
directly, so it only rounds at assignment/conversion.顺便说一句,如果你定义像
operator+=
这样的赋值运算符,那么Complex<X>
只会在左边(没有友元函数)并且只返回Complex<X>&
(类型是固定的。)它可能应该接受与operator+
或直接使用operator+
,所以它只在赋值/转换时四舍五入。
template<class Y>
auto operator+=(Y const& y)
-> std::enable_if<std::is_arithmetic_v<Y>,
Complex>& { /*...*/ }
I assume that you don't want to use std::complex
for some reason.我假设您出于某种原因不想使用
std::complex
。 Now you have to decide the type of complex<float>+double
;现在你必须决定
complex<float>+double
的类型; is it going to loose some data?它会丢失一些数据吗?
complex<float>
, then precision bits of double
are lost and large values are clamped to INF
.complex<float>
,则double
的精度位会丢失,并且较大的值会被限制为INF
。double
, then the imaginary part is gone.double
,那么虚部就消失了。 Thus, the best of both worlds would be complex<double>
.因此,两全其美将是
complex<double>
。 A closer looks reveals that your problem boils down to conversion/promotion to/from numeric types.仔细观察会发现您的问题归结为数字类型的转换/提升。 You are going to need conversion constructors:
您将需要转换构造函数:
#include <concept>
template<std::floating_point numeric>
class complex{
public:
constexpr complex(numeric const r=0,numeric const i=0);
template<std::floating_point othern>
requires std::constructible_from<numeric,othern>
explicit(!std::convertible_to<othern, numeric>)
constexpr complex(complex<othern> const&);
//...
Now you can simply define:现在您可以简单地定义:
//continue class declaration:
friend auto const& operator(complex rgt, complex const& lft)
{return rgt+=lft;};
complex const& operator+=(complex const&);
//...
This approach hits two birds with one stone.这种方法用一块石头击中两只鸟。 For completness I would define one conversion operator too:
为了完整起见,我也会定义一个转换运算符:
//still inside class complex:
explicit constexper operator numeric() const
{return this->real();};
//...
The explicit
specifiers - in declaration of conversion constructors and operator - conducts correct deduction and required implicit. explicit
说明符 - 在转换构造函数和运算符的声明中 - 进行正确的推导和所需的隐式。 conversions转换
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.