Зажим с помощью real_t от Godot- cpp - PullRequest
0 голосов
/ 10 апреля 2020

Я пытаюсь использовать зажим, но не могу его найти

Сводный пример

Файл: 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);
}

VS C ошибка, скомпилируйте с помощью scons:

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

Большое спасибо!

1 Ответ

2 голосов
/ 11 апреля 2020

Проблема в том, что 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 lvalues.

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);

Технически это не относится к вашей строке с типом переменной 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;
}

Обратите внимание, что в этом случае важно, чтобы функция возвращала побочное значение потому что оператор ?: может привести к значению prvalue в зависимости от типов аргументов.

Также подумайте, действительно ли вы хотите использовать clamp с различными типами аргументов (это относится как к реализации, которую я показываю выше, а также макрос, который вы используете). Вы можете легко случайно выполнить непреднамеренные сравнения, например, если один из аргументов является целым числом со знаком, а другой - без знака, сравнение с < даст непредвиденные результаты. Вероятно, поэтому стандартная библиотека не допускает разные типы аргументов.

...