Аргументы шаблона первого типа шаблона

Я использую 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 и лямбда-выражений, сгенерированных во время выполнения?

Почему бы не сделать параметры функций min и max?

NathanOliver 09.05.2018 20:16

Мне следовало пояснить, что я работаю в среде C++ 11, поэтому значение автоматического возврата не является вариантом.

dfreese 09.05.2018 20:24

И я не делал их в параметрах функции, поскольку API принимает обратный вызов только с одним параметром. Я мог бы просто написать лямбду при установке обратного вызова, но это шаблон, который я хотел бы сделать кратким и ясным, поскольку он многократно используется повторно.

dfreese 09.05.2018 20:37

Проблема здесь именно в том, что тип float исключен из шаблонов функций? Не могли бы вы написать альтернативную спецификацию для чисел с плавающей запятой, где 2 аргумента значений были двойными?

Gem Taylor 09.05.2018 21:10

@GemTaylor double также не допускаются в качестве аргументов, не относящихся к типу.

Justin 09.05.2018 21:11

Вы уверены, что используете среду C++ 11? В вашем примере вы пишете static_assert() без сообщения об ошибке, которое, если я правильно помню, является функцией C++ 17.

max66 09.05.2018 21:13

Справедливо. У меня было смутное воспоминание, что именно поплавки были исключены из типов pemplate. В прошлом я разрешал эту проблему, изобретая представление перечисления с фиксированной точкой, но это действительно не очень красиво. Конечно, в конкретном примере они могут быть целыми числами!

Gem Taylor 09.05.2018 21:14

@ max66, правильно. Я добавил статическое утверждение для примера и забыл об этом. Фактический код фактически не использует это.

dfreese 09.05.2018 21:16

А как насчет пользовательских литералов? :-)

Gem Taylor 09.05.2018 21:18
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
5
9
163
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Поскольку числа с плавающей запятой не допускаются как параметры шаблона, не являющиеся типами, вы должны принимать как фактические аргументы функции, а не параметры шаблона.

Если вы хотите иметь функцию, которая принимает только один аргумент, вы можете избежать затрат на 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 - нет. Итак, это ответ на процитированный вопрос.

max66 09.05.2018 21:05

Что делает статические глобальные переменные допустимыми, а литералы - нет? Я не знаком с этим.

dfreese 09.05.2018 21:25

Ах, не понимал, что это из-за поплавка. stackoverflow.com/questions/2183087/…

dfreese 09.05.2018 21:30

@dfreese: Дело в том, что это скорее ссылки. Ссылки на самом деле являются замаскированными указателями, которые удовлетворяют интегральному ограничению аргументов шаблона.

AndyG 09.05.2018 21:31

@dfreese - точно: ваш исходный пример не работает, потому что значения с плавающей запятой не разрешены аргументом шаблона (14.1.7: «Параметр шаблона без типа не должен объявляться как имеющий тип с плавающей запятой, класс или тип void» ). Но, в той же точке стандарта, есть пример, показывающий, что указатель или ссылка на double в порядке в качестве аргумента шаблона без типа.

max66 09.05.2018 21:34

Другие вопросы по теме