6

考虑以下愚蠢的例子:

class MyClass
{
    public:
        template <class Function> 
        inline double f(double x, Function&& function)
        {
            return function(x);
        }
};

有了这个类,我可以调用MyClass::f(x, function),使用 lambda 函数来执行它x,(我希望)没有开销。我的问题是:function作为 的可设置成员,什么是等效的MyClass

class MyClass
{
    public:
        inline double f(double x)
        {
            return _function(x);
        }
    // What are the setter and the type of the protected member _function ?
};
4

2 回答 2

10

Lambda 函数(以及一些其他类型的“可调用”函数)可以使用标头std::function中的模板类进行包装和存储<functional>。它的模板参数是一个函数签名,语法如下

ReturnType(ArgumentType1, ArgumentType2, ...)

所以在你的情况下,整个函数包装类型变成

std::function<double(double)>

因此,您的代码变为

class MyClass
{
    public:
        inline double f(double x)
        {
            return _function(x);
        }
        void setFunction(std::function<double(double)> && f)
        {
            _function = f;
        }
    private:
        std::function<double(double)> _function;
};

std::function比函数指针的包装“更多”。您可能知道,lambda 函数可以捕获需要存储在某处的变量上下文的一部分。std::function透明地为你做这件事。

请注意,std::function不支持函子的重载签名/模板化调用运算符。T operator()(T value)当使用像a这样的调用操作符签名分配函子时,std::function<double(double)>只能使用此签名调用它。所以没有std::function<T(T)>(除非T已经知道,比如你的类的模板参数)。


在某些情况下可能更有效的替代方法(您需要对其进行基准测试/分析)是使您的整个类成为模板类,其中函数类型参数是模板参数。然后您可以将函数存储为成员:

template<typename Function>
class MyClass
{
    public:
        MyClass(Function && f) :
            _function(f)
        {}
        inline double f(double x)
        {
            return _function(x);
        }
    private:
        Function _function;
};

为了创建这样的对象,您需要指定模板参数,如下所示:

auto myLambda = [](double x){ return x * 0.25; };
MyClass<decltype(myLambda)> myObject { myLambda };

为了避免这种难看的语法开销,添加一个利用模板类型推导的“maker”函数:

template<typename Function>
auto makeMyClass(Function && f) -> MyClass<Function> {
    return MyClass<Function>(f);
}

然后,代码变得更具可读性,auto再次使用:

auto myLambda = [](double x){ return x * 0.25; };
auto myObject = makeMyClass(myLambda);
于 2013-05-21T10:15:09.933 回答
3

您必须使用std::function包装器,可能让构造函数从输入的可调用对象初始化它:

#include <functional> // <== REQUIRED FOR std::function

class MyClass
{
    public:

        template<typename F>
        MyClass(F&& f) : _function(std::forward<F>(f)) { }

        inline double f(double x)
        {
            return _function(x);
        }

    private:

        std::function<double(double)> _function;    
};

请注意,这可能会给您带来一些运行时开销,但设计简单且灵活。除非您可以证明此运行时开销是软件性能要求的瓶颈,否则此运行时开销不应成为问题。

于 2013-05-21T10:14:51.143 回答