与 Godot-cpp 的 real_t 一起使用

Clamp using with real_t from Godot-cpp

我正在尝试使用 clamp,但找不到它

一个总结示例

文件:test.h

#ifndef DEMO_H
#define DEMO_H

#include <algorithm>

namespace demo {

   typedef float real_t;
   class test {
       public:
           void start();
           real_t x = 10.90;
           real_t y = 2.10;
       test();
       ~test();
   };
}

#endif //DEMO_H

文件:test.cpp

#include "test.h"

using namespace demo;

void test::start() {
    const int& p = std::clamp(x, 0,  y);
}

VSC错误,使用scons编译:

no overloaded function instance "std :: clamp" matches the argument list - argument types are: (real_t, int, real_t)

非常感谢!

问题是std::clamp声明如下:

template<class T>
constexpr const T& clamp(const T&, const T&, const T&);

这意味着所有三个参数必须具有相同的类型。如果未明确指定模板参数,则推导将失败,因为成功的模板参数推导要求从中推导模板参数的所有函数参数产生相同的类型。

但在您的示例中,您使用:

std::clamp(x, 0,  y);

依次使用 floatintfloat 类型的函数参数。因此,第一个和第三个函数参数会将 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 returns 它的参数之一是引用。所以可能会发生第二个参数real_t(0),它是一个临时参数,通过引用返回。但是那个临时的在行

之后被销毁了
    const auto& p = std::clamp(x, real_t(0),  y);

所以 p 可能是一个悬空引用。而是按值存储结果:

    auto p = std::clamp(x, real_t(0),  y);

这在技术上不适用于变量类型为 const int& 的行,因为它与从 std::clamp 返回的引用之间的类型不匹配将导致创建一个临时的,然后绑定到p 并延长使用寿命。但这不是一个应该依赖的东西。


在您的评论中 link 您应该将 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;
}

请注意,在这种情况下,函数 returns 按值很重要,因为 ?: 运算符可能会根据参数类型产生纯右值。

还要仔细考虑您是否真的想将 clamp 与不同的参数类型一起使用(这适用于我上面显示的实现以及您正在使用的宏)。您很容易意外地进行意外比较,例如,如果一个参数是有符号整数而另一个参数是无符号整数,则与 < 的比较将产生意外结果。这可能就是标准库不允许不同参数类型的原因。