std :: clamp - 检测函数返回值是否绑定到const T&

vla*_*don 6 c++ template-meta-programming clamp c++17

std::clamp如果其中一个minmax参数是rvalues ,最好不要将返回值绑定到const ref .

典型的实现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;
}
Run Code Online (Sandbox Code Playgroud)

正如已经在std :: clamp的cppreference中所述,当有人写道时会出现危险的情况:

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

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

Jus*_*tin 2

如果您愿意编写自己的钳位函数,您可以检测到这一点并采取措施。

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

#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;
}
Run Code Online (Sandbox Code Playgroud)

这将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;
}
Run Code Online (Sandbox Code Playgroud)