Я начал создавать библиотеку управления разрешениями, Основная идея заключается в том, что у вас есть какая-то конфигурация, считанная из файла, и на ее основе вы можете выполнить функциональный объект, который будет обертывать функции «разрешить» и «ограничить».
Код пока разделен на несколько частей
У меня есть диспетчер разрешений, который говорит, может ли быть выполнен данный "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"}
Он будет работать с новым кодом, это правда, но я хотел упростить обертывание существующего класса моей библиотекой, не прибегая к дополнительным усилиям по написанию лямбда-выражений для всего.
Я действительно не понимаю, что вы имеете в виду под «приложить дополнительные усилия для написания лямбда-выражений для всего». Что «дополнительного» в использовании лямбда-выражений? Вам нужно как-то зарегистрировать свои обратные вызовы, с помощью лямбды будет не намного больше печатать, чем с помощью bind
, скорее меньше
Во-первых, я подумал, что может быть метод, упрощающий его, чтобы вы могли сделать что-то вроде: some_template<decltype(member_f)> wrapper_member{member_f, member_f, &tpm, "resource"} аналогично тому, что я делаю в другом случае, но после того, как посмотрите на лямбды, этот подход тоже может работать, я думал, что это больше усилий, чем просто вызов члена. Я думал, вам нужно аналогичным образом связать это, но похоже, что вы можете просто захватить его, и это просто работает.
some_template<decltype(member_f)> wrapper_member{member_f, member_f, &tpm, "resource"}
возможно, добавьте это к вопросу, потому что в настоящее время не на 100% ясно, какова ваша цель из вопроса
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)...)));
};
}
вы уже используете лямбда-выражения в своем первом примере, так почему бы не использовать их и для функций-членов?