使用C ++中的variate模板实现的apply函数的延迟评估

时间:2013-10-23 20:53:08

标签: c++ templates lazy-evaluation

我正在尝试使用variate模板编写自己的apply函数。这是我的代码:

    template<typename...>
    struct types{
    };

    template<typename T, typename... Args>
    struct Func{
        template<typename F, typanem... Types>
        T call(F f, std::tuple<Types...>& params, Args... args){
            return _call(f, params, types<Types...>{}, args...);
        }
        template<typename F, typename Tuple, typename Head, typename... Tail, typename... Args>
        T _call(F f, Tuple& t, types<Head, Tail...>, Args&&... args){
            _call(f, t, types<Tail...>{}, std::forward<Args>(args)..., std::get<sizeof...(Arg)>(t).DrawSample()));
        }
        T _call(F f, Tuple& t, types<>, Args... vs){ 
            return f(vs...)
        }
    };

我可以毫无困难地编译和运行上面的代码。现在我想让函数调用(...)被懒惰地调用。换句话说,我可以通过传入计算所需的所有参数来构造函数:

    int getMax(float f1, float f2, float f3){
      if(f1 >= f2 && f1 >= f3){
          return 1;
      }
      if(f2 >= f1 && f2 >= f3){
          return 2;
      }
      if(f3 >= f1 && f3 >= f2){
          return 3;
      }
    }
    Func<int> func;
    //Gaussian(mu, sd) is an object which can generate random values based on Gaussian 
    //distribution described with mu(mean) and sd(standard deviation).
    Gaussian *g1 = Gaussian(0.3, 0.2);
    Gaussian *g2 = Gaussian(0.2, 0.3);
    Gaussian *g3 = Gaussian(0.3, 0.3);
    func.setCall(getMax, std::make_tuple(*g1, *g2, *g3);
    cout<<func.DrawSample();

构造函数之后,我希望每次查询func.DrawSample()时都会懒惰地获取getMax()函数的结果。在引擎盖下,也许DrawSample()调用call(...)。但是,无论如何,我是否需要更改上面的代码才能创建一个setCall(...),其目的是存储以后函数调用所需的所有内容?

如果我的问题仍然不清楚,请告诉我。非常感谢你的帮助!

3 个答案:

答案 0 :(得分:0)

使用std::function<int()>和lambdas。

std::function<int()> func;
func = [=]()->int {
  return getMax( Guassian(0.3,0.2), Guassian(0.2,0.3), Guassian(0.3,0.3) );
};
std::cout << func();

如果您确实需要自己的界面,只需在std::function<T()>内存储classsetCall只需指定即可。

但实际上,您的对象是一些匿名类型,可以调用它来生成int - std::function解决问题。无论如何你都必须进行类型擦除,因为你的类的类型不包括函数签名,所以你可能不会更有效率。

答案 1 :(得分:0)

试试这个:

template<class Func, class... Args>
    int applyDrawSample(Func func, Args... args)
{
    return func(args.DrawSample()...);
}

template<class Func, class... Args>
    auto bind_helper(Func func, Args... args)
    -> decltype(bind(applyDrawSample<Func, Args...>, func, args...))
{
    return bind(applyDrawSample<Func, Args...>, func, args...);
}

用法:

auto func = bind_helper(getMax, Gaussian(...), Gaussian(...), Gaussian(...));

func();

一个简单的额外lambda可以将最后一次调用更改为func->DrawSample(),如果你真的想要它,并留作练习。

修改

如果您需要上面func的类型,则可以是std::function

function<int()> func = bind_helper(...);

int的函数签名(在本例中为无参数的函数,返回std::function)需要与您指定的内容兼容。

答案 2 :(得分:0)

根据DanielKO提供的建议,我终于为我的具体方案提出了一个解决方案。 这是我编译代码的最终版本。

    template<class Func, class... Args>
    int applyDrawSample(Func func, Args&&... args){
        return func((*args).DrawSample()...);
    }
    template<class Func, class... Args>
    auto bind_helper(Func func, Args&&... args) ->decltype(bind(applyDrawSample<Func, Args...>,  
        func, args...))
    {
        return bind(applyDrawSample<Func, Args...>, func, args...);
    }

    template<typename T>
    struct UncertainFunc{
        template<typename F, typename... Args>
        void setFunc(F f, Args... args){
            function = bind_helper(f, args...);
        }
        T DrawSample(){
            return function();
        }
        std::function<T()> function;
    };

    UncertainFunc<int> ufunc;
    ufunc.setFunc(getMax, &(Gaussian(0.3, 0.2), &Gaussian(0.2, 0.3), &Gaussian(0.2, 0.2));
    ufunc.DrawSample();

特别是,由于某些原因(似乎是自动类型?),我似乎无法将bind_helper(...)函数放入我的类定义中。