如何编写包含变量和参数的通用Functor类?

时间:2014-07-02 14:59:49

标签: templates generics c++11 tuples variadic

出于数学目的,我想编写一个通用仿函数类来包含带有变量和参数的简单数学方程。想象一下简单的抛物线:

y=f(x;a,b,c)=a*x*x+b*x+c  

此处abc是为一个抛物线设置一次的参数。那么 纵坐标值y是通过提供某些值来计算的 变量x。我用variadic编写了一个简单的gen_func类 模板与std::tuple组合用于保存参数和a 变量的可变参数包。这堂课的骨架是 发现于How to store variadic template arguments?

我是新c ++ 11标准的新手,我知道写得正确 使用可变参数模板的代码是一件非常复杂的事情。

出于某些目的,我想通过 call-by-reference 来更改变量。但在这里,编译器(gcc 4.7)确实抱怨。为简单起见,我通过简单的功能更改测试了代码。它的唯一目的是改变传递的第一个变量的值。这是一个简单程序的代码:

#include <tuple>
#include <iostream>
#include <functional>
#include<utility>
using namespace std;

// Compile with : g++ -o X.bin -Wall -pedantic -std=c++11 X.cpp 

// Stuff for compile-time recursive parameter pack expansion:
namespace generic
{
    template <std::size_t... Ts>
    struct index_sequence {}; 

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

    template <std::size_t... Ts>
    struct sequence_generator<0, Ts...> : index_sequence<Ts...> {};

    template<  typename ReturnType , typename... Args  > using generic_function_pointer = ReturnType (*) (  Args... args  ) ;

}


// The generic Function wrapper: 
template < typename R , class F , typename... Ps>
class gen_func
{
    public:
        // Constructor
        gen_func(F&& f,Ps&&...parms){
            func = forward<F>(f); 
            parameters=make_tuple(forward<Ps>(parms)...);
        }
        // execute-Function for public call:
        template<typename... Vars>
        R execute(Vars&&... vars) { 
           return f_decon<Vars... , Ps...>( forward<Vars>(vars)... , parameters );
        }
        //
    private:
         // "Deconvolution Function"
        template<typename... Vars , typename... Ts >
        R f_decon( Vars&&... vars , tuple<Ts...>& tup ){
            return f_proxy<Vars...,Ps...>( forward<Vars>(vars)... , tup , generic::sequence_generator<sizeof...(Ts)>{} );
        }
        // "Proxy-Function" calling the wrapped Function func:
        template<typename... Vars , typename... Ts , size_t... Is>
        R f_proxy( Vars&&... vars , tuple<Ts...>& tup , generic::index_sequence<Is...> ){
            return func( forward<Vars>(vars)... , get<Is>(tup)... );
        }
        // The wrapped Function f
        F func;
        // The tuple holding optional parameters for function f:
        tuple<Ps...> parameters; 

};

// Partial template Specialization of gen_func for Functions with Return Type void:
template <class F , typename... Ps>
class gen_func<void,F,Ps...>
{
    public:
        // Constructor
        gen_func(F&& f,Ps&&...parms){
            func = forward<F>(f); 
            parameters=make_tuple(forward<Ps>(parms)...);
        }
        // execute-Function for public call:
        template<typename... Vars>
        void execute(Vars&&... vars) { 
           f_decon<Vars... , Ps...>( forward<Vars>(vars)... , parameters );     // Line 75
        }
        //
    private:
        // The wrapped Function f
        F func;
        // The tuple holding optional parameters for function f:
        tuple<Ps...> parameters;
         // "Deconvolution Function"
        template<typename... Vars , typename... Ts >                            
        void f_decon( Vars&&... vars , tuple<Ts...>& tup ){                     // Line 85
            f_proxy<Vars...,Ts...>( forward<Vars>(vars)... , tup , generic::sequence_generator<sizeof...(Ts)>{} );
        }
        // "Proxy-Function" calling the wrapped Function func:
        template<typename... Vars , typename... Ts , size_t... Is>
        void f_proxy( Vars&&... vars , tuple<Ts...>& tup , generic::index_sequence<Is...> ){
            func( forward<Vars>(vars)... , get<Is>(tup)... );
        }
};

void change(int& m,int n){
    cout << "Changing!" << endl;
    int res=42+n;
    m=res;
}  

int main()
{

typedef generic::generic_function_pointer<void,int&,int>  chg_ptr;

gen_func<void,chg_ptr> y(change);

// The Variable to be altered by change    
int j=0;
cout << "j='" << j << "'" << endl; // should be 0
// Wrapped Function call:
y.execute(j,21);                                        // Line 113
cout << "j='" << j << "'" << endl; // should be 63

return 0;
}  

编译器确实抱怨:

X.cpp: In instantiation of ‘void gen_func<void, F, Ps ...>::execute(Vars&& ...) [with Vars = {int&, int}; F = void (*)(int&, int); Ps = {}]’:
X.cpp:113:15:   required from here
X.cpp:75:12: error: no matching function for call to ‘gen_func<void, void (*)(int&, int)>::f_decon(int&, int, std::tuple<>&)’
X.cpp:75:12: note: candidate is:
X.cpp:85:14: note: template<class ... Vars, class ... Ts> void gen_func<void, F, Ps ...>::f_decon(Vars&& ..., std::tuple<_Args2 ...>&) [with Vars = {Vars ...}; Ts = {Ts ...}; F = void (*)(int&, int); Ps = {}]
X.cpp:85:14: note:   template argument deduction/substitution failed:
X.cpp:75:12: note:   mismatched types ‘std::tuple<_Elements ...>’ and ‘int’

似乎通过引用传递变量x来使代码错误,以便可以通过包装函数更改来更改它。我的计划方法完全错了吗?纠正是否简单?有没有更好的方法来实现我的目标?提前感谢任何建议!

0 个答案:

没有答案