Функция-член передается как std::function в шаблон, привязывая все параметры

Я начал создавать библиотеку управления разрешениями, Основная идея заключается в том, что у вас есть какая-то конфигурация, считанная из файла, и на ее основе вы можете выполнить функциональный объект, который будет обертывать функции «разрешить» и «ограничить».

Код пока разделен на несколько частей

У меня есть диспетчер разрешений, который говорит, может ли быть выполнен данный "std::string" или нет:

class PermissionManager {
    public:
        virtual bool canAccess(std::string resource) {return true;};
};

Затем у меня есть фактическая оболочка для функции:

template <typename FuncT>
class PermissionFunction {
private:
    FuncT m_restrict;
    FuncT m_allow;
    PermissionManager *m_pManager;
    std::string m_resource;

public:
    PermissionFunction(const PermissionFunction&) = delete;
    PermissionFunction& operator=(const PermissionFunction&) = delete;
    PermissionFunction(FuncT r, FuncT a, PermissionManager *man, std::string res)
        : m_restrict(r), m_allow(a), m_pManager(man), m_resource(res){
    }

    template<typename ...ARG>
    typename std::result_of<FuncT(ARG&&...)>::type operator()(ARG&&... args){
        if (m_pManager->canAccess(m_resource)){
            return m_allow(std::forward<ARG>(args)...);
        } else {
            return m_restrict(std::forward<ARG>(args)...);
        }
    }

};

Итак, использование примерно такое:

PermissionManager tpm{};
std::function<void(int)> testRestrict = [](int a){std::cout << "Restrict" << std::endl;};
std::function<void(int)> testAllow = [](int a){std::cout << "Allow" << std::endl;};
PermissionFunction<decltype(testRestrict)> testPerm(testRestrict, testAllow, &tpm, "hi");
for(int i = 0; i <10; i++){
    testPerm(i);
}

Это работает очень хорошо для std::functions, не являющегося членом, однако, когда я хочу определить его с помощью функции-члена, это становится очень грязным:

class test {
    public:
        void testato(int i){
            std::cout << i << std::endl;
        }
    PermissionManager perm{};
    PermissionFunction<std::function<void(int)>>
permf{
      std::bind(&test::testato, this, std::placeholders::_1),
      std::bind(&test::testato, this, std::placeholders::_1),
      &perm, "hi"};
};

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

Цель состояла бы в том, чтобы объявление функции было похоже на объявление std::functions в приведенном примере, чтобы я мог определить объект-член следующим образом:

some_template<decltype(member_f)> 
wrapper_member{member_f, member_f, &tpm, "resource"} 

Где member_f — фактическая функция-член класса. В идеале тип должен быть выведен, но я думаю, что было бы допустимо повторить его и таким образом:

some_template<return_t(args_t)>
wrapper_member{member_f, member_f, &tpm, "resource"} 

вы уже используете лямбда-выражения в своем первом примере, так почему бы не использовать их и для функций-членов?

463035818_is_not_a_number 11.06.2019 11:01

Он будет работать с новым кодом, это правда, но я хотел упростить обертывание существующего класса моей библиотекой, не прибегая к дополнительным усилиям по написанию лямбда-выражений для всего.

cerkiewny 11.06.2019 11:15

Я действительно не понимаю, что вы имеете в виду под «приложить дополнительные усилия для написания лямбда-выражений для всего». Что «дополнительного» в использовании лямбда-выражений? Вам нужно как-то зарегистрировать свои обратные вызовы, с помощью лямбды будет не намного больше печатать, чем с помощью bind, скорее меньше

463035818_is_not_a_number 11.06.2019 11:56

Во-первых, я подумал, что может быть метод, упрощающий его, чтобы вы могли сделать что-то вроде: some_template<decltype(member_f)> wrapper_member{member_f, member_f, &tpm, "resource"} аналогично тому, что я делаю в другом случае, но после того, как посмотрите на лямбды, этот подход тоже может работать, я думал, что это больше усилий, чем просто вызов члена. Я думал, вам нужно аналогичным образом связать это, но похоже, что вы можете просто захватить его, и это просто работает.

cerkiewny 11.06.2019 12:02
some_template<decltype(member_f)> wrapper_member{member_f, member_f, &tpm, "resource"} возможно, добавьте это к вопросу, потому что в настоящее время не на 100% ясно, какова ваша цель из вопроса
463035818_is_not_a_number 11.06.2019 12:03
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
5
88
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

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

C++20 представляет std::bind_front, который связывает аргументы только с начальными параметрами и поэтому не требует использования объектов-заполнителей. Его можно использовать, чтобы сделать ваш код более кратким.

PermissionFunction<std::function<void(int)>> permf{
  std::bind_front(&test::testato, this),
  std::bind_front(&test::testato, this),
  &perm, "hi"};

Возможная реализация С++ 17:

#include <tuple>
#include <utility>

template <typename F, typename... Xs>
auto bind_front(F&& f, Xs&&... xs)
{
  return [
    f = std::forward<F>(f),
    xs = std::make_tuple(std::forward<Xs>(xs)...)](auto&&... ys) -> decltype(auto)
  {
    return std::apply(
      f,
      std::tuple_cat(xs, std::forward_as_tuple(std::forward<decltype(ys)>(ys)...)));
  };
}

возможно std::forward_as_tuple?

Caleth 11.06.2019 14:09

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