Я использую API, который принимает функцию с одним аргументом в качестве обратного вызова. Обратный вызов принимает единственный аргумент определенного типа и для простоты я скажу, что он возвращает bool. Главное, что я пытался собрать, - это функция проверки диапазона. Моя интуиция могла бы написать что-то вроде этого:
template<class T, T min, T max>
constexpr bool in_range(T val) {
return (val >= min && val <= max);
}
static_assert(in_range<float, 0.0f, 1.0f>(0.5f), "doesn't work")
Однако это не сработало, поэтому я по умолчанию создал функцию таким образом.
template<class T>
std::function<bool(T)> in_range(T min, T max) {
auto test = [min, max](T val) {
return (val >= min && val <= max);
};
return test;
}
assert(in_range<float>(0.0f, 1.0f)(0.5f))
Есть ли способ написать функцию больше в форме первой функции, чтобы я не зависел от std::function и лямбда-выражений, сгенерированных во время выполнения?
Мне следовало пояснить, что я работаю в среде C++ 11, поэтому значение автоматического возврата не является вариантом.
И я не делал их в параметрах функции, поскольку API принимает обратный вызов только с одним параметром. Я мог бы просто написать лямбду при установке обратного вызова, но это шаблон, который я хотел бы сделать кратким и ясным, поскольку он многократно используется повторно.
Проблема здесь именно в том, что тип float исключен из шаблонов функций? Не могли бы вы написать альтернативную спецификацию для чисел с плавающей запятой, где 2 аргумента значений были двойными?
@GemTaylor double также не допускаются в качестве аргументов, не относящихся к типу.
Вы уверены, что используете среду C++ 11? В вашем примере вы пишете static_assert() без сообщения об ошибке, которое, если я правильно помню, является функцией C++ 17.
Справедливо. У меня было смутное воспоминание, что именно поплавки были исключены из типов pemplate. В прошлом я разрешал эту проблему, изобретая представление перечисления с фиксированной точкой, но это действительно не очень красиво. Конечно, в конкретном примере они могут быть целыми числами!
@ max66, правильно. Я добавил статическое утверждение для примера и забыл об этом. Фактический код фактически не использует это.
А как насчет пользовательских литералов? :-)





Поскольку числа с плавающей запятой не допускаются как параметры шаблона, не являющиеся типами, вы должны принимать как фактические аргументы функции, а не параметры шаблона.
Если вы хотите иметь функцию, которая принимает только один аргумент, вы можете избежать затрат на std::function, вернув лямбда напрямую. Если бы мы использовали C++ 14, вы могли бы просто вернуть auto:
template<class T>
auto in_range(T min, T max) { // Note: could be `constexpr` in C++17
return [min, max](T val) {
return (val >= min && val <= max);
};
}
Однако, поскольку вы используете C++ 11, вам придется вручную записать вызываемый тип:
template <typename T>
class InRange {
public:
constexpr InRange(T min, T max)
: min(std::move(min))
, max(std::move(max))
{}
constexpr bool operator()(T const& val) const {
return (val >= min && val <= max);
}
private:
T min;
T max;
};
template<class T>
constexpr InRange<T> in_range(T min, T max) {
return InRange<T>(std::move(min), std::move(max));
}
Is there a way to write the function more in the form of the first function, so I'm not depending on std::function and lambdas generated at runtime?
Если вы можете передавать статические глобальные переменные в качестве аргумента шаблона вместо литералов float, вы можете передавать их по ссылке.
Что-то вроде следующего
#include <iostream>
template <typename T, T const & min, T const & max>
constexpr bool in_range (T val)
{ return (val >= min && val <= max); }
static constexpr float f0 { 0.0f };
static constexpr float f1 { 1.0f };
int main ()
{
static_assert(in_range<float, f0, f1>(0.5f), "!");
}
@Barry - float эталонного шаблона принимаются в качестве параметра шаблона, а простые параметры float - нет. Итак, это ответ на процитированный вопрос.
Что делает статические глобальные переменные допустимыми, а литералы - нет? Я не знаком с этим.
Ах, не понимал, что это из-за поплавка. stackoverflow.com/questions/2183087/…
@dfreese: Дело в том, что это скорее ссылки. Ссылки на самом деле являются замаскированными указателями, которые удовлетворяют интегральному ограничению аргументов шаблона.
@dfreese - точно: ваш исходный пример не работает, потому что значения с плавающей запятой не разрешены аргументом шаблона (14.1.7: «Параметр шаблона без типа не должен объявляться как имеющий тип с плавающей запятой, класс или тип void» ). Но, в той же точке стандарта, есть пример, показывающий, что указатель или ссылка на double в порядке в качестве аргумента шаблона без типа.
Почему бы не сделать параметры функций
minиmax?