Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setter of a lambda function?

Consider the following dumb example :

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

With this class, I can call MyClass::f(x, function), with a lambda function to execute it on x, with (I hope) no overhead. My question is : what would be the equivalent with the function as a settable member of the MyClass ?

class MyClass
{
    public:
        inline double f(double x)
        {
            return _function(x);
        }
    // What are the setter and the type of the protected member _function ?
};
like image 342
Vincent Avatar asked May 21 '13 10:05

Vincent


People also ask

Can we replace lambda expression with method reference?

To summarize: If the purpose of the lambda expression is solely to pass a parameter to an instance method, then you may replace it with a method reference on the instance. If the pass-through is to a static method, then you may replace it with a method reference on the class.

Can we declare variable in lambda expression?

A lambda expression can't define any new scope as an anonymous inner class does, so we can't declare a local variable with the same which is already declared in the enclosing scope of a lambda expression. Inside lambda expression, we can't assign any value to some local variable declared outside the lambda expression.

What is a BiConsumer?

Interface BiConsumer<T,U> Represents an operation that accepts two input arguments and returns no result. This is the two-arity specialization of Consumer . Unlike most other functional interfaces, BiConsumer is expected to operate via side-effects.


1 Answers

Lambda functions (as well as some other types of "callable" functions) can be wrapped and stored using the std::function template class, found in the <functional> header. Its template parameter is a function signature with the syntax

ReturnType(ArgumentType1, ArgumentType2, ...)

so in your case the whole function wrapper type becomes

std::function<double(double)>

and thus, your code becomes

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 is "more" than a wrapper for function pointers. As you might know, lambda functions can capture part of the variable context, which needs to be stored somewhere. std::function does this for you transparently.

Note that std::function does not support overloaded signatures / templated call operators for functors. When assigning a functor with a call-operator signature like T operator()(T value) to a std::function<double(double)>, it can only be called with this signature. So there is no std::function<T(T)> (unless T is already known, such as a template parameter of your class).


An alternative which might be more efficient in some cases (you need to benchmark / profile it), is to make your whole class a template class with the function type parameter being the template parameter. Then you can store a function as a member:

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

In order to create such an object, you need to specify the template parameter, like this:

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

To avoid this ugly syntactic overhead, add a "maker" function which takes advantage of template type deduction:

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

Then, the code becomes more readable, with use of auto again:

auto myLambda = [](double x){ return x * 0.25; };
auto myObject = makeMyClass(myLambda);
like image 68
leemes Avatar answered Oct 28 '22 17:10

leemes