问题是std::clamp
声明如下:
template<class T>
constexpr const T& clamp(const T&, const T&, const T&);
这意味着所有三个参数必须具有相同的类型。如果没有显式指定模板参数,那么推导将失败,因为成功的模板参数推导要求从其中推导出模板参数的所有函数参数产生相同的类型。
但是在您的示例中,您使用:
std::clamp(x, 0, y);
它按顺序使用float
,类型int
的函数参数。float
因此,第一个和第三个函数参数将推断T
为float
,但第二个函数参数会将其推断为int
,从而导致推断失败,从而导致重载决议失败。
确保使用相同的类型:
std::clamp(x, real_t(0), y);
在行
const int& p = std::clamp(x, 0, y);
您使用了错误的类型p
。我假设你的意思是real_t
,不是int
。您可以使用以下方法避免此类类型不匹配auto
:
const auto& p = std::clamp(x, 0, y);
此外,std::clamp
如果不是所有参数都是左值,则将结果存储到引用也不会保存std::clamp
。
std::clamp
通过引用返回其参数之一。所以可能会发生第二个参数real_t(0)
,它是一个临时的,通过引用返回。但是那个临时的在线路之后被破坏了
const auto& p = std::clamp(x, real_t(0), y);
所以p
可能是一个悬空的参考。而是按值存储结果:
auto p = std::clamp(x, real_t(0), y);
这在技术上不适用于带有变量 type 的行const int&
,因为它与返回的引用之间的类型不匹配std::clamp
将导致创建一个临时对象,然后将绑定到p
并延长其生命周期。但这不是一个人应该依赖的东西。
clamp
在您链接的评论中,您应该作为宏的替代实现。
这里的宏作为一个重大缺点:它将多次评估其参数。如果您想要一个std::clamp
接受不同类型的替代方案,那么您可以自己将其编写为函数模板,例如:
template<typename T, typename U, typename V>
constexpr auto clamp(const T& t, const U& u, const V& v) {
return (t < u) ? u : (v < t) ? v : t;
}
请注意,在这种情况下,函数按值返回很重要,因为?:
运算符可能会根据参数类型产生纯右值。
Also think carefully about whether you actually want to use clamp
with different argument types (This applies to both the implementation I show above as well as the macro you are using). You could easily accidentally make unintended comparisons, for example if one of the arguments is a signed integer and the other an unsigned one, the comparison with <
will yield unintended results. This is probably why the standard library does not allow different argument types.