【问题标题】:Template type deduction warns returning reference to local temporary object模板类型推导警告返回对本地临时对象的引用
【发布时间】:2018-12-30 16:00:13
【问题描述】:

考虑这些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 参数 max() 返回一个 char * 值到你的三个参数 max(),然后通过引用返回该临时参数。

标签: c++ templates type-deduction


【解决方案1】:

main:

auto result = max(a, b, c);T = const char* 调用第三个重载,因为它是唯一可行的重载(三个参数)。

在那个函数中:

max(a,b) 调用第二个重载:对于第一个重载T = const char* 是通过模板参数推导选择的。然后,出于函数重载的目的,重载一和二中的所有参数都被视为完全匹配。这是因为第一次重载不需要转换,而第二次重载只需要左值到右值的转换。因此,由于转换序列的原因,两个重载都不是首选(转换序列的附加排序规则也不适用),而是选择重载两个,因为非模板函数优于模板函数。

对于外部调用max(max(a,b),c),与上述相同的推理适用,只是第一个参数是const char* 类型的右值表达式,使得第二个重载和第一个重载的左值到右值转换是不必要的引用绑定也被认为是完全匹配。同样,没有任何附加的转换顺序排序规则适用。

因此后一个表达式的返回值是一个临时的const char*,它将绑定到第三个重载返回的引用。

【讨论】:

    【解决方案2】:

    您从中间的 2 参数 max() 到三个参数 max() 按值返回一个 char *,然后通过引用返回该临时参数。

    相反,也可以通过 ref 获取 char*。您还需要在 3-way max 上丢失 const,以免最终得到 const char * const。最重要的是,您还需要正确处理右值,我认为下面的代码至少更接近于这样做。您必须考虑一个 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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2010-11-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-04
      相关资源
      最近更新 更多