模板类型推断警告返回对本地临时对象的引用

时间:2018-12-30 16:00:14

标签: c++ templates type-deduction

请考虑以下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;
}

能否请您一步一步解释在此示例中如何推导类型,从而导致将本地引用返回给临时对象?

2 个答案:

答案 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;
}

https://godbolt.org/z/sMo9dx