微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

使用变量模板转发Linux系统调用的代理

如何解决使用变量模板转发Linux系统调用的代理

我有一个类,该类在调用特定系统调用之前会进行一些功能处理。这是通过可变参数模板函数完成的:

class PrivilegesLinux
{
private:
    //! Prevent type deduction on template parameter.
    template<typename T> struct NoDeduce { typedef T type; };

public:

template<typename... PAR>
static int syscallProxy(cap_value_t capability,int(*syscall)(PAR...),typename NoDeduce<PAR>::type... params)
    {
        int rc = 0;
        // ... acquire capabilities

        // Forward to system call
        rc = (*syscall)(params...);

        // ... drop capabilities

        return rc;
    }
//...
};

这在“正常”系统调用上很好用。从模板参数推导出系统调用的签名。 typename NoDeduce<PAR>::type... params对实际参数强制使用非推导上下文。一旦我有支持C ++ 20的编译器,就可以用std::type_identity代替。这是一个使用此功能获取kill系统调用特权的示例:

PrivilegesLinux::syscallProxy(CAP_KILL,kill,1,SIGTERM);

但是,一旦我尝试使用签名中带有...的系统调用(例如ioctl),就会收到编译器错误在这里尝试更改MTU大小) :

PrivilegesLinux::syscallProxy(CAP_NET_ADMIN,ioctl,nSocketID,SIOCSIFMTU,(char *)&ifr);
/*
error: no matching function for call to 'PrivilegesLinux::syscallProxy(int,int (&)(int,long unsigned int,...) noexcept,const INT32&,int,char*)'
note: candidate: 'static int PrivilegesLinux::syscallProxy(cap_value_t,int (*)(PAR ...),typename PrivilegesLinux::NoDeduce<PAR>::type ...) [with PAR = {int,long unsigned int}; cap_value_t = int]'
note:   candidate expects 4 arguments,5 provided
*/

很显然,省略号作为参数包的一部分在这里引起了此问题。我以为可以使用std::forward解决此问题:

template<typename... PAR>
static int syscallProxy(cap_value_t capability,typename NoDeduce<PAR>::type&&... params)
{
    //...
    rc = (*syscall)(std::forward<PAR>(params)...);
    //...
}

但是,此操作失败并显示

error: cannot bind rvalue reference of type 'PrivilegesLinux::NoDeduce<long unsigned int>::type&&' {aka 'long unsigned int&&'} to lvalue of type 'pthread_t' {aka 'long unsigned int'}

有人建议使用单个模板功能来完成这项工作吗? 我当前的解决方法是定义另一个模板:

template<typename... SYSCALL_PAR,typename... PAR>
static int syscallProxy(cap_value_t capability,int(*syscall)(SYSCALL_PAR...,...),PAR... params)
{
    // copy of the code above
}

解决方法

如何逆转推论:函数的通用类型(避免推论参数的类型)并推论参数(也许添加转发)?

我的意思是...类似

template <typename Func,typename... PARS>
static int syscallProxy (cap_value_t capability,Func syscall,PARS && ... params)
 {
   int rc = 0;
   // ... acquire capabilities

   // Forward to system call
   rc = syscall(std::forward<PARS>(params)...);

   // ... drop capabilities

   return rc;
 }
,

或者,您可以通过添加额外的重载来显式处理C省略号:

template<typename... PAR,typename ... Ts>
static int syscallProxy(cap_value_t capability,int(*syscall)(PAR...,...),typename NoDeduce<PAR>::type... params,Ts... args) // ellipsis arguments
{
    // Possibly check Ts... are "valid" type for ellipsis
    int rc = 0;
    // ... acquire capabilities

    // Forward to system call
    rc = (*syscall)(params...,args...);

    // ... drop capabilities

    return rc;
}

注意:

  • int(*syscall)(PAR...,...)也可能写为int(*syscall)(PAR......)
  • Ts通过值传递,因为ellipsis arguments types仍然受到限制。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?