# Generic<Programming>: 再谈Min和Max

Andrei Alexandrescu
ye_feng译　本文代码

##### Min和Max

#define min(a, b) ((a) < (b) ? (a) : (b))


template <class T>
const T& min(const T& lhs, const T& rhs)
{
return lhs < rhs ? lhs : rhs;
}


double a, b;
...
min(a, b) += 2;


template <class T>
T& min(T& lhs, T& rhs)
{
return lhs < rhs ? lhs : rhs;
}


int a;
short int b;
...
int smallest = min(a, b); // error: can't figure out T
// in template instantiation


int smallest = min(a, int(b)); // aha, T is int


##### 一个（几乎是）好的开始

template <class L, class R>
class MinResult {
L& lhs_;
R& rhs_;
public:
operator L&() { return lhs_ < rhs_ ? lhs_ : rhs_; }
operator R&() { return lhs_ < rhs_ ? lhs_ : rhs_; }
MinResult(L& lhs, R& rhs) : lhs_(lhs), rhs_(rhs) {}
};

template <class LR>
class MinResult<LR, LR> {
LR& lhs_;
LR& rhs_;
public:
operator LR() { return lhs_ < rhs_ ? lhs_ : rhs_; }
MinResult(LR& lhs, LR& rhs) : lhs_(lhs), rhs_(rhs) {}
};

template <class L, class R>
MinResult min(L lhs, R rhs)
{
return MinResult(lhs, rhs);
}


int a, b;
...
min(a, b);


int c = min(a, b);


int a;
short int b;
extern Fun(int);
extern Fun(short int);
...
Fun(min(a, b)); // error! Don't know which overload to invoke!

MaxResult<int, short int>支持两种转换：转成int&和转成short int&。结果编译器无法在Fun的两个重载版本中决定选择哪一个。而基于宏的方法再一次通过了测试，如你所期望的那样，最终会调用Fun(int)。
##### 寻找一个类型

template <class L, class R>
MINTYPE(L, R)
Min(L& lhs, R& rhs)
{ return lhs < rhs ? lhs : rhs; }

template <class L, class R>
MINTYPE(const L, R)
Min(const L& lhs, R& rhs)
{ return lhs < rhs ? lhs : rhs; }

template <class L, class R>
MINTYPE(L, const R)
Min(L& lhs, const R& rhs)
{ return lhs < rhs ? lhs : rhs; }

template <class L, class R>
MINTYPE(const L, const R)
Min(const L& lhs, const R& rhs)
{ return lhs < rhs ? lhs : rhs; }


#define MINTYPE(L, R) typename MinTraits<L, R>::Result

template <class L, class R> struct MinTraits;

// Specialization for the L == R case
template <class LR> struct MinTraits<LR, LR> {
typedef LR& Result;
};

// Specialization for bool and char
template <> struct MinTraits<bool, char> {
typedef char Result;
};

...


class Shape {
...
unsigned int Area() = 0;
};

bool operator<(const Shape& lhs, const Shape& rhs) {
return lhs.Area() < rhs.Area();
}

class Rectangle : public Shape { ... };

void Hatch(Shape& shape)
{
Rectangle frame;
...
Shape& smallest = Min(shape, frame);
... use smallest ...
}


shape < frame ? shape : frame


shape < frame ? shape : Shape(frame)


##### Loki

Okey，刚才我撒谎了。代码只有80行，但这没有把使用的类库计算在内。更确切地说，我用了Loki，在我写的书[5]里介绍的一个通用库。在众多功能中，Loki提供了高级的类型操纵手段。Min实现里用到的Loki工具有：

1. Typelists。除了保存的是类型而不是值外，Typelists[6]和通常的列表一样。例如下面语句：

typedef TYPELIST_3(float, double, long double) FloatingPointTypes;


Loki::TL::IndexOf<FloatingPointTypes, double>::value


2. 我们要用到的第二个工具是Select类模板，它在[7]里有详细描述。简单来说，Select允许你根据一个编译时的布尔常量在两个类型中选择一个。例如：

typedef Loki::Select<sizeof(wchar_t) <
sizeof(short int), wchar_t, short int>::Result
SmallInt;


3. TypeTraits该类模板可以进行各种关于类型的推演，例如“这个类型是指针吗？它指向什么类型？”等等。我们只用到TypeTraits中的NonConstType类型定义。TypeTraits<T>::NonConstType是一个typedef，用来去掉T的const修饰，如果有的话。

4. 最后，我们会用到Conversion类[7]，它可以检测任意一个类型是否可以被隐式地转换为另一个类型。Conversion是实现上面提到的关于Shape和Rectangle的魔术的基础。

##### MinMaxTraits类模板

namespace Private
{
typedef TYPELIST_14(
const bool,
const char,
const signed char,
const unsigned char,
const wchar_t,
const short int,
const unsigned short int,
const int,
const unsigned int,
const long int,
const unsigned long int,
const float,
const double,
const long double)
ArithTypes;
}


先假设Result为R。

如果R可以被隐式地转换为L，那么把Result改成L。

如果L和R是算术类型，并且在上面的Private::ArithTypes里R排在L后面，那么把Result改为R。这一步用来处理所有算术转换。

如果L&可以被自动转换为R&，而不需要引入临时变量，那么把Result改为R&。这一步确保Min(frame, shape) 之类的调用返回Shape&。

如果R&可以被自动转换为L&，而不需要引入临时变量，那么把Result改为L&。这一步确保Min(shape,frame) 之类的调用返回Shape&。

##### Min和Max重载函数

Min和Max各有四个重载函数，对应于const和非const参数的四种组合。为了防止上面Shape/Rectangle例子里所讨论的对象切片（slicing）问题，Min的实现和经典的a < b ? a : b略有不同：

template <class L, class R>
typename MinMaxTraits<L, R>::Result
Min(L& lhs, R& rhs)
{ if (lhs < rhs) return lhs; return rhs; }

template <class L, class R>
typename MinMaxTraits<const L, R>::Result
Min(const L& lhs, R& rhs)
{ if (lhs < rhs) return lhs; return rhs; }

.. similar Max implementation ...


##### 分析

1. 提供函数调用的语义（包括类型检查），而不是宏的语义。Min显然可以做到。

2. 支持const和非const参数（包括在同一个调用里混用）。由于那四个重载函数，Min支持const和非const参数的任意组合。

3. 支持两个不同类型的参数（当然指有意义的情况）。Min的确支持不同类型的参数，而且还有很多宏和简单模板方法所达不到的智能：Min会分辨各种算术类型，并进行合理的转换。类型转换的选择过程（基于Private::ArithTypes）可以由库的作者控制。

4. 不需要显式实例化。Min不需要显式实例化。

Min对于指针也可以正确工作（甚至指向不同但有关联的类型的指针，如Shape*和Rectangle*）。这是由于算法中的第一步。

##### 参考书目

[1] http://www.aristeia.com/Papers/C++ReportColumns/jan95.pdf

[2] http://www.cuj.com/experts/1902/alexandr.htm

[3] http://www.gotw.ca/gotw/077.htm

[4] A. Alexandrescu. "Traits: the else-if-then of Types," C++ Report, April 2000.

[5] A. Alexandrescu. Modern C++ Design (Addison-Wesley Longman, 2001).

[6] J. Vlissides and A. Alexandrescu. "To Code or Not to Code," C++ Report, March 2000.

[7] A. Alexandrescu. "Generic: Mappings between Types and Values," C/C++ Users Journal Experts Forum, September 2000, http://www.cuj.com/experts/1810/alexandr.htm.

[8] R. Kurzweil. The Age of Spiritual Machines: When Computers Exceed Human Intelligence (Penguin USA, 2000).

• 本文已收录于以下专栏：

## Java中的泛型编程(generic programming)和泛型类(generic class)

• lichengyu
• 2015年12月06日 10:49
• 1677

## 《Generic Programming and the STL》读书笔记

Generic Programming and the STL   最后还需要把没搞懂的地方一一记下列出搞懂，争取一次把STL吃透，并在工作中学以致用!!别囫囵吞枣！ 译序 作为一个广为人知的...
• backard
• 2013年01月23日 20:07
• 662

## Generic Programming in C++

2.1 Introduction In generic programming, we take the notion of an ADT a step further. Instead of wr...
• seamanj
• 2016年02月15日 23:48
• 635

## python奇技淫巧——max/min函数的用法

• IAlexanderI
• 2017年04月15日 16:22
• 2256

## 生成在[min,max]之间的随机整数

• caixiajia
• 2016年10月14日 11:07
• 930

## 同时max(),min()取最大 最小值 在mysql和Oracle中的差别

mysql 可以同时取最大值和最小值: mysql> explain select max(uuid) from p300; +----+-------------+-------+------+--...
• zhaoyangjian724
• 2016年12月26日 14:30
• 775

## SQL语句中MAX()函数和MIN()函数

MAX 函数返回一列中的最大值。NULL 值不包括在计算中。 SELECT MAX(column_name) FROM table_name 注释：MIN 和 MAX 也可用于文本列，以获...
• anlidengshiwei
• 2014年12月29日 15:41
• 1531

## max与min函数的概率分布思考

max与min函数的概率分布思考@(概率论)给定一样本序列则： max(X1,X2,...,Xn)≤a⟺X1≤a,X2≤a,...,Xn≤amax(X_1,X_2,...,X_n) \leq a \...
• u011240016
• 2016年11月19日 09:16
• 1864

## vc中对标准库std::min,max,swap的支持问题

• vipcowrie
• 2007年10月12日 08:50
• 4811

## python: min 和 max 函数

• xingchengmeng
• 2017年03月22日 16:31
• 3018

举报原因： 您举报文章：Generic: 再谈Min和Max 色情 政治 抄袭 广告 招聘 骂人 其他 (最多只允许输入30个字)