简体   繁体   English

为我自己的函数执行通常的算术转换?

[英]Performing the usual arithmetic conversions for my own function?

This came up at work today, so I thought I would throw it out to the community. 今天就出现了,所以我想我会把它扔给社区。

A co-worker wrote the following code (more or less): 一位同事编写了以下代码(或多或少):

#include <algorithm>

double chop(double x) {
    return std::max(0, x);
}

But this does not even compile, because std::max wants both of its arguments to have the exact same type. 但是这甚至都没有编译,因为std::max希望它的两个参数都具有完全相同的类型。 I believe this is so it can take a pair of references and return a reference, which is very likely what you want if you invoke it on a user-defined type. 我相信这是如此,它可以采取一对引用并返回一个引用,如果你在用户定义的类型上调用它,很可能是你想要的。 Fair enough. 很公平。

The fix, of course, is to use std::max(0.0, x) . 当然,修复是使用std::max(0.0, x)

Now bear with me for a moment, because I lied. 现在忍受我一会儿,因为我撒了谎。 What my coworker actually wrote was this: 我的同事实际写的是这样的:

// Included from a very old header file written by someone long gone
template<class T1, class T2>
inline T1 myMax(T1 x, T2 y) {
    return (x < y) ? y : x;
}

double chop(double x) {
    return myMax(0, x);
}

This compiles! 这编译! But it produces rather surprising results for x equal to, say, 0.25. 但它产生了相当令人惊讶的结果,x等于0.25。 I am not sure how long it took him to find the problem, and even after finding it, he had to ask why it was not working. 我不确定他找到问题需要多长时间,甚至在找到问题之后,他不得不问为什么它不起作用。

My answer was (a) Use 0.0 instead of 0 (which fixes the bug), and (b) use std::max instead of myMax (whose behavior is quite frightening when you think about it). 我的回答是(a)使用0.0而不是0(修复bug),以及(b)使用std::max而不是myMax (当你想到它时,它的行为非常可怕)。

But he is wondering why that has to be. 但他想知道为什么会这样。 I mean, he can write 0 + x or 0 * x or 0 - x , so why not myMax(0, x) ? 我的意思是,他可以写0 + x0 * x0 - x ,那为什么不是myMax(0, x)

Here is my first pass at giving him what he wants: 这是我第一次给他他想要的东西:

// this is from the .hh file

// template meta-program to compute the "wider" of two types given as argument
template<class T1, class T2>
struct WiderType {
};

// Partial specialization for case where both types are same
template<class T>
struct WiderType<T, T> {
  typedef T type;
};

// Specialization for first type "int" and second type "double"
template<>
struct WiderType<int, double> {
  typedef double type;
};

template<class T1, class T2>
inline typename WiderType<T1,T2>::type
myMax(T1 a, T2 b) {
  return ((a < b) ? b : a);
}


// this is from the .cc file

double chop(double x) {
  return myMax(0, x);
}

// just to show this still works
int chop(int x) {
  return myMax(0, x);
}

Now, I could go through and add a specialization for WiderType for every pair of integral types, plus some to do the other Usual Arithmetic Conversions. 现在,我可以为每对整数类型添加WiderType的特化,还有一些用于其他常用算术转换。 (And I guess I could rename it UsualConversions or somesuch.) (我想我可以将它重命名为UsualConversions或者其他一些。)

But is there an easier way? 但是有更简单的方法吗? That is, does the C++ language give me a simple way to define my own function that performs the same conversions on its arguments as the various built-in arithmetic operators? 也就是说,C ++语言是否为我提供了一种简单的方法来定义我自己的函数,该函数在其参数上执行与各种内置算术运算符相同的转换?

In addition to Charles Bailey's answer, you can do this as well: 除了Charles Bailey的回答,你也可以这样做:

template<typename T1, typename T2>
typename std::common_type<T1, T2>::type max(T1&& a, T2&& b) {
    return a < b ? b : a;
}

common_type has a typedef type in it that is the type that both types can be implicitly converted to, so if it were, for instance, double and int , it would return a double , but if it were int and int , it would return an int . common_type有一个typedef type ,它是两个类型都可以隐式转换为的类型,所以如果它是,例如, doubleint ,它将返回一个double ,但如果它是intint ,它将返回一个int

If you can't use C++11 at all, then the only thing I can think of is this: 如果你根本不能使用C ++ 11,那么我唯一能想到的是:

template<typename T1, typename T2, typename T3>
void max(const T1& a, const T2& b, T3& dst) {
    dst = a < b ? b : a;
}

and use it like 并使用它

double d;
max(0, 43.12, d);

It's pretty clumsy having to declare a variable that way though. 不过必须以这种方式声明变量是非常笨拙的。 If you think it's prettier, you can also do this: 如果你认为它更漂亮,你也可以这样做:

template<typename RetType, typename T1, typename T2>
RetType max(const T1& a, const T2& b) {
    return a < b ? b : a;
}

and then 接着

return max<double>(0, 43.11);

I don't know of a good way before C++11 but now you can do something like this. 我不知道在C ++ 11之前的好方法,但现在你可以做这样的事情。

template<class T, class U>
auto myMax(T&& t, U&& u) -> decltype(t + u)
{
    return t < u ? u : t;
}

decltype(t + u) just works out what the common type for T and U would be in an arithmetic expression and uses that as the return type for the template. decltype(t + u)只计算出TU的常用类型在算术表达式中的含义,并将其用作模板的返回类型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM