如何解决使用变量模板转发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 举报,一经查实,本站将立刻删除。