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

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

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

У меня есть менеджер разрешений, который говорит, может ли данный "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"};
};

Мне интересно, есть ли способ сократить использование типов переменных-членов, я тоже думал об использовании шаблона для этого, но я не уверен, как использовать std bind с параметрами шаблона 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"} 

1 Ответ

4 голосов
/ 11 июня 2019

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"};

Возможная реализация C ++ 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<decltype(ys)>(ys)...));
  };
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...