我想允许多个签名用于其类型被指定为模板参数的可调用对象。更具体地说,我有一个模板update
方法,它采用一个必须返回float
的可调用方法,并使用它来更新数据网格中的值。对此的简化说明是
template <typename Fn>
void update(Fn&& fn_)
{
for (Vec3 pos : m_grid)
{
float val = fn_(pos, m_grid)
m_grid(pos) = val;
...
在上述情况下,fn_
的签名必须始终同时包含pos和grid作为参数,即使它们在实现中被忽略
我想使用一些模板魔术来允许多个回调签名的排列。
特别是,我想允许采用pos
而不是grid
的回调,以及根本不采用任何参数的回调。我不介意是否强制执行参数排序。
任何有关如何做到这一点的提示?我不介意使用boost或其他库,但它们应该只是标题。
答案 0 :(得分:1)
您可以使用is_invocable
std::is_invocable
:boost::callable_traits::is_invocable
使用SFINAE,或使用C++17之前使用SFINAE执行此操作:template <typename Fn,
std::enable_if_t<std::is_invocable<Fn, Vec3, Grid>::value>* = nullptr>
float call_helper(Fn&& fn_, const Vec3& pos_, const Grid& grid_)
{
return fn_(pos_, grid_);
}
template <typename Fn,
std::enable_if_t<std::is_invocable<Fn, Vec3>::value>* = nullptr>
float call_helper(Fn&& fn_, const Vec3& pos_, const Grid& grid_)
{
return fn_(pos_);
}
template <typename Fn,
std::enable_if_t<std::is_invocable<Fn, Grid>::value>* = nullptr>
float call_helper(Fn&& fn_, const Vec3& pos_, const Grid& grid_)
{
return fn_(grid_);
}
template <typename Fn>
void update(Fn&& fn_)
{
for (Vec3 pos : m_grid)
{
float val = call_helper(fn_, pos, m_grid)
m_grid(pos) = val;
...
)
% sudo systemctl start mongodb
答案 1 :(得分:1)
特别是,我想允许采用pos而不是grid的回调,以及根本没有参数的回调。
只需定义两个重载并使用lambdas通过将请求转发到完整函数来执行此操作,从而过滤额外参数。
作为一个最小的工作示例:
struct S {
template <typename Fn>
auto update(Fn &&fn_)
-> decltype(fn_(0, 0), void())
{
// ...
fn_(0, 0);
// ...
}
template <typename Fn>
auto update(Fn &&fn_)
-> decltype(fn_(0), void())
{ update([&fn_](auto a, auto) { fn_(a); }); }
template <typename Fn>
auto update(Fn &&fn_)
-> decltype(fn_(), void())
{ update([&fn_](auto, auto) { fn_(); }); }
};
int main() {
S s;
s.update([](auto, auto) {});
s.update([](auto) {});
s.update([]() {});
}