C ++:通用函数包装类作为非模板类​​

时间:2016-10-28 02:37:22

标签: c++ c++11 function-pointers wrapper variadic-templates

我正在尝试实现一个卡尔曼滤波器类,它可以接受用户提供的测量模型函数,该函数可以包含任意数量的参数。如果你不熟悉卡尔曼滤波器并不重要,基本上我有一个非模板类,它有一个模板化的构造函数,它接收一个包含任意类型参数的函数。然后构造函数将传递的函数分配给函数包装器成员对象,该对象本身是基于可变参数模板类构造的。我遇到的问题是如何在不知道将传递给构造函数的函数的特定形式的情况下将函数包装器对象声明为我的Kalman过滤器类的成员?

如果不是很清楚,我道歉。但是,我基本上一直在关注this回答this问题,其中行auto add = make_action([] (int a, int b) { std::cout << a + b; }, 2, 3)表示我想要作为成员变量合并到我的非模板类中的功能(使用赋值发生在构造函数中。)

这是我的代码:

#include <iostream>
#include <functional>
#include <tuple>

namespace Helper
{
    template <std::size_t... Ts>
    struct Index {};

    template <std::size_t N, std::size_t... Ts>
    struct GenSeq : GenSeq<N-1, N-1, Ts...> {};

    template <std::size_t... Ts>
    struct GenSeq<0, Ts...> : Index<Ts...> {};
}

template <typename... ArgTps>
class MeasModWrapper
{
private:
    std::function<void(ArgTps...)> MeasMod;
    std::tuple<ArgTps...> MeasModArgs;

public:
    template <typename MsModFnc, typename... ArgTs>
    MeasModWrapper( MsModFnc&& MsMod, ArgTs&&... args )
        :    MeasMod( std::forward<MsModFnc>(MsMod) ),
             MeasModArgs( std::make_tuple( std::forward<ArgTs>(args)... ) )
    {}

    template <typename... ArgTs, std::size_t... Is>
    void MsMod( std::tuple<ArgTs...>& tup, Helper::Index<Is...> )
    {
        MeasMod( std::get<Is>(tup)... );
    }

    template <typename... ArgTs>
    void MsMod( std::tuple<ArgTs...>& tup )
    {
        MsMod( tup, Helper::GenSeq<sizeof...(ArgTs)>{} );
    }

    void CallMeasMod( void )
    {
        MsMod( MeasModArgs );
    }
};

template <typename MsModFnc, typename... ArgTs>
MeasModWrapper<ArgTs...> BindMeasMod( MsModFnc&& MsMod, ArgTs&&... args )
{
    return MeasModWrapper<ArgTs...>( std::forward<MsModFnc>( MsMod ), std::forward<ArgTs>( args )... );
}

// The following is where my code differs from the solution provided by user 0x499602D2 (many thanks btw)
class KF
{
private:
    auto measurementModel;              // <--- This doesn't work, and I expected that it wouldn't, but how can I get around this problem???

public:
    template <typename MsFnc, typename... FncArgs>
    KF( MsFnc&& msFnc, FncArgs&&... fncArgs )
        :    measurementModel( BindMeasMod( msFnc ), std::forward<FncArgs>( fncArgs )... )
    {}

    void CallMeasMod( void )
    {
        measurementModel.CallMeasMod();
    }
};

int main( void )
{
    KF kf([](int x, int y){ std::cout << (x+y) << std::endl; }, 3, 4 );         // Just a simple example function - in reality it could take any form and most likely wouldn't be a lambda function, but that's not particularly important at this stage.
    kf.CallMeasMod();
    //auto measurementModel = BindMeasMod([] (int a, int b) { std::cout << a + b << std::endl; }, 3, 4);        // <-- This would work because it by-passess the KF class - BUT it is not what I want
    //measurementModel.CallMeasMod();
    return 0;
}

我确信如果KF类是模板类,问题可能会大大简化,但我真的不想这样做。我不知道Boost是否会提供一些实现我想要的方法,但如果可能的话,我更喜欢基于STL的解决方案。非常感谢能够为我提供任何帮助的人。

我对可变参数模板相当新,说实话我仍然觉得它们有点令人困惑(例如,我不是100%确定Helper命名空间中的代码是如何工作的)所以如果有人也可以推荐一本好书或者网站能够很好地解释它们(对于傻瓜),那也是值得赞赏的。

P.S。我在Ubuntu 14.04上使用g ++ 4.8.4,如果这很重要的话。

编辑:

我忘了提到我正在尝试建立一个图书馆。 KF类将具有许多附加功能,但这是卡尔曼滤波器的所有实现的标准。每个实现的不同之处在于测量模型(和过程模型,但我没有在此示例中包含它,因为它将以与测量模型相同的方式处理)所以我需要能够处理任何类型的函数有任意数量的参数,然后有一个共同的方式在幕后的KF类本身的各个点调用该函数(我在这里包含的代码显示在主函数中调用的测量模型函数,但实际上它将不在这里调用。它将在KF类中使用,其精确形式未知)。该库将由工程师使用,该工程师将提供用作测量模型的特定函数,因此他/她将在构造KF类期间指定函数的名称及其参数,并且可以预期这将是一个常规的,非模板化的功能。我在这个例子中只使用了一个简单的lambda函数,因为它整齐地安装在一行上,并且它也用在了我所遵循的例子中。

1 个答案:

答案 0 :(得分:0)

不清楚这对你有什么好处,但这会让你的榜样有效:

#include <iostream>
#include <functional>

class KF
{
private:
    std::function<void()> measurementModel;

public:
    template <typename MsFnc, typename... FncArgs>
    KF( MsFnc&& msFnc, FncArgs&&... fncArgs )
        :    measurementModel([=]() { return msFnc(fncArgs...); })
    {}

    void CallMeasMod( void )
    {
        measurementModel();
    }
};

int main( void )
{
    KF kf([](int x, int y){ std::cout << (x+y) << std::endl; }, 3, 4 );
    kf.CallMeasMod();
    return 0;
}

Demo