7

如果它的或参数之一是右值,最好不要将std::clamp返回值绑定到 const ref 。minmax

典型实现std::clamp(非常简化):

template <class T>
constexpr const T& clamp(const T& value, const T& min, const T& max)
{
    return value < min ? min : max < value ? max : value;
}

正如cppreference for std::clamp中已经说明的那样,当有人写时存在危险情况:

int n = -1;
const int& r = std::clamp(n, 0, 255);
// r is dangling

有没有办法在编译时检测这些情况?

4

1 回答 1

2

如果您愿意编写自己的钳位函数,则可以检测到这一点并对其进行处理。

例如,假设您希望clamp 函数按值返回,如果这是确保我们不会得到悬空引用的唯一方法:

#include <type_traits>

template<class A, class B, class C>
constexpr std::conditional_t<
    std::is_lvalue_reference<A &&>::value && std::is_lvalue_reference<B &&>::value && std::is_lvalue_reference<C &&>::value,
    std::add_lvalue_reference_t<std::common_type_t<A, B, C>>,
    std::common_type_t<A, B, C>
> clamp(A && value, B && min, C && max)
{            
    return value < min ? min : max < value ? max : value;
}

这将使clamp(n, 0, 255)签名有效int clamp(int&, int&&, int&&)int & clamp(int&, int&, int&)只有当所有 3 个输入都是左值引用时,你才会得到。const如果您愿意,制作返回的参考是微不足道的。

如果它们不是所有的左值引用,您也可能无法编译该函数:

#include <type_traits>

template<class A, class B, class C>
constexpr std::add_lvalue_reference_t<std::common_type_t<A, B, C>>
    clamp(A && value, B && min, C && max)
{
    static_assert(std::is_lvalue_reference<A &&>::value && std::is_lvalue_reference<B &&>::value && std::is_lvalue_reference<C &&>::value, "");

    return value < min ? min : max < value ? max : value;
}
于 2017-02-06T17:52:14.787 回答