允许lambda / callback函数的多个签名作为模板参数

时间:2017-11-04 17:30:01

标签: c++ templates lambda c++14 variadic-templates

我想允许多个签名用于其类型被指定为模板参数的可调用对象。更具体地说,我有一个模板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或其他库,但它们应该只是标题。

2 个答案:

答案 0 :(得分:1)

您可以使用is_invocable std::is_invocableboost::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([]() {});
}