将成员函数作为std :: function传递给模板,并绑定所有参数

时间:2019-06-11 08:52:25

标签: c++ templates

我已经开始构建权限管理库, 基本思想是,您可以从文件中读取某种配置,并基于此配置可以执行将包装“ 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绑定与普通模板参数一起使用,它具有适用于任何功能类型。

目标是使函数声明类似于给出的示例中带有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 个答案:

答案 0 :(得分:4)

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)...));
  };
}
相关问题