我看到了模板函数 max 的示例代码。
template <typename T1,
typename T2,
typename RT = std::decay_t<decltype(true ? std::declval<T1>()
: std::declval<T2>())>>
RT max (T1 a, T2 b) {
return b < a ? a : b;
}
我知道什么是
decltype
和declval
。但我不明白为什么它使用总是 true 的三元运算符来推断返回类型。
如果我使用
max(1, 2.5)
,它会返回double
类型的2.5
,这意味着RT
被推导为第二个参数T2
或double
。即使 decltype
仅返回 T1
的类型,怎么可能?
(我知道我可以使用
auto
作为返回类型来简化代码。但我的目的是了解奇怪代码的用法。)
decltype(true ? std::declval<T1>() : std::declval<T2>())
是一个穷人试图获得 T1
和 T2
的“普通类型”。据推测,如果 T1 = int
和 T2 = double
,则应为 double
,因为 int
在诸如 double
之类的表达式中将转换为 int{...} + double{...}
。
我说poor-man's是因为
std::declval
返回一个右值引用,所以RT
将是一个右值引用,而这个函数模板基本上无法使用。您可以按如下方式验证:
template int&& max(int, int); // explicit instantiation
这会产生以下编译器错误(https://godbolt.org/z/3dWzvh9v3):
<source>:8:12: error: rvalue reference to type 'int' cannot bind to lvalue of type 'int' 8 | return b < a ? a : b; | ^~~~~~~~~~~~~ <source>:11:16: note: in instantiation of function template specialization 'max<int, int, int &&>' requested here 11 | template int&& max(int, int); |
更好的定义是:
template <typename T, typename U, typename R = std::common_type_t<T, U>>
R max(T a, U b) {
return b < a ? a : b;
}
或者:
// C++20 abbreviated function template
// C++11 trailing return type with decltype
auto max(auto a, auto b) -> decltype(b < a ? a : b) {
return b < a ? a : b;
}