请考虑以下max
函数:
template<typename T>
const T& max(const T& a, const T& b) {
return b < a ? a : b;
}
// overload max(a, b) for char* arguments
const char* max(const char* a, const char* b) {
return std::strcmp(b, a) < 0 ? a : b;
}
template<typename T>
const T& max(const T& a, const T& b, const T& c) {
return max(max(a,b), c);
}
现在,当调用三个参数max
时,它将返回正确的结果。但是,它还会在编译过程中显示“返回对本地临时对象的引用”。
int main() {
const char* a = "aaa";
const char* b = "bbb";
const char* c = "ccc";
auto result = max(a, b, c);
// this correctly prints "ccc"
std::cout << result << std::endl;
return 0;
}
能否请您一步一步解释在此示例中如何推导类型,从而导致将本地引用返回给临时对象?
答案 0 :(得分:3)
在main
中:
auto result = max(a, b, c);
用T = const char*
调用第三个重载,因为它是唯一可行的重载(三个参数)。
在该功能中:
max(a,b)
调用第二个重载:对于第一个重载T = const char*
由模板参数推导选择。然后,出于函数重载的目的,将重载1和2中的所有参数都视为 exact match 。这是因为对于第一次过载,不需要转换,而对于第二次过载,仅需要从左值到右值的转换。因此,由于转换序列的缘故,两个重载都不是优选的(转换序列的其他排序规则均不适用),而是选择两个重载,因为非模板函数比模板函数更可取。
对于外部调用max(max(a,b),c)
,采用与上述相同的推理,只是第一个参数是类型为const char*
的右值表达式,从而无需进行第二次重载的左值到右值转换,并且对于第一个重载引用绑定,也被视为完全匹配。同样,没有其他附加的转换顺序排序规则适用。
因此,后一个表达式的返回值是一个临时const char*
,它将绑定到第三个重载返回的引用。
答案 1 :(得分:1)
您从中间的2参数max()返回值三个字符max()的char *,然后通过引用返回该临时值。
相反,也请通过引用获取char *。您还需要在3路最大值上丢失const,以免最终无法获得const char * const's。最重要的是,您还需要正确处理右值,我认为以下代码至少更接近这样做。您必须考虑一个r值合格的运算符<。
#include <string.h>
#include <type_traits>
#include <utility>
struct C {
bool operator<(C const & c) && {return false;}
};
// overload max(a, b) for char* arguments
const char*& max(const char*& a, const char*& b) {
return strcmp(b, a) < 0 ? a : b;
}
template<typename T>
decltype(auto) max(T&& a, T&& b) {
return std::forward<T>(b) < std::forward<T>(a) ? std::forward<T>(a) : std::forward<T>(b);
}
template<typename T>
decltype(auto) max(T&& a, T&& b, T&& c) {
return max(max(std::forward<T>(a), std::forward<T>(b)), std::forward<T>(c));
}
int main() {
const char* a = "aaa";
const char* b = "bbb";
const char* c = "ccc";
auto result = max(a, b, c);
// this correctly prints "ccc"
max(1, 2, 3);
max("a", "b", "c");
max (C(), C(), C());
return 0;
}