21

I want a way to make functor from function. Now I trying to wrap function call by lambda function and instantiate it later. But compiler says than lambda constructor is deleted. So is there any way to compile this code ? Or maybe another way for that ?

#include <iostream> void func() { std::cout << "Hello"; } auto t = []{ func(); }; typedef decltype(t) functor_type; template <class F> void functor_caller() { F f; f(); } int main() { functor_caller<functor_type>(); return 0; } 

Now I get such compiler error:

error: use of deleted function '<lambda()>::<lambda>()' error: a lambda closure type has a deleted default constructor 

In my opinion the only way is to use macro:

#define WRAP_FUNC(f) \ struct f##_functor \ { \ template <class... Args > \ auto operator()(Args ... args) ->decltype(f(args...)) \ { \ return f(args...); \ } \ }; 

then

WRAP_FUNC(func); 

and then (in main)

functor_caller<func_functor>() 
6
  • I cannot even declare a variable of type functor_type in main. Need to get that to work first. Commented Jun 17, 2012 at 16:50
  • 1
    @user315052: That is actually the same problem. Commented Jun 17, 2012 at 16:51
  • Did you try F f(t); ? Currently, functor_caller doesn't know about t. Commented Jun 18, 2012 at 6:59
  • No. I don't want to use it. I try get type of lambda and than default construct it. Commented Jun 18, 2012 at 7:52
  • @Andigor: That doesn't make sense. There's no default value for lambda types. The compiler tells you as much (no default ctor). Commented Jun 18, 2012 at 10:03

5 Answers 5

8

The code doesn't make sense. Imagine you have a capturing lambda like this:

{ int n = 0; auto t = [&n](int a) -> int { return n += a; }; } 

What could it possibly mean to default-construct an object of type decltype(t)?

As @Matthieu suggests, you could wrap the lambda into a function object:

std::function<int(int)> F = t; 

Or you could template your call-site directly on the type of the lambda (or any callable entity):

template <typename F> int compute(int a, int b, F f) { return a * f(b); // example } 

Usage: int a = 0; for (int i : { 1, 3, 5 }) { a += compute(10, i, t); }

If at all possible, the second style is preferable, since the conversion to std::function is a non-trivial, potentially expensive operation, as is the actual function call through the resulting object. However, if you need to store a uniform collection of heterogeneous callable entities, then std::function may well be the easiest and most convenient solution.

Sign up to request clarification or add additional context in comments.

2 Comments

Theoretically default constructing of lambda in your example means that I get reference to n which can be dangle reference if that object was destructed. But if n lives I got correct reference.
@Andigor: If you use the templaty style, then you don't even need to construct an intermediate functor - you can just pass the function (pointer) directly... and note that n isn't necessarily in scope, nor is it meaningfully part of the type.
8

Lambdas do not have default constructors. Ever. The only constructors they sometimes give access to is (depending on what they capture) the copy and/or move constructors.

If you create a functor with no public default constructor, you'll get the same error.

In C++17 you can solve this with constexpr lambda and operator+ to decay-to-function pointer. A type that carries a function pointer and invokes it is easy with auto template parameters.

In C++11 you gotta get a bit hacky.

template<class F> struct stateless_lambda_t { static std::aligned_storage_t< sizeof(F), alignof(F) >& data() { static std::aligned_storage_t< sizeof(F), alignof(F) > retval; return retval; }; template<class Fin, std::enable_if_t< !std::is_same< std::decay_t<Fin>, stateless_lambda_t >{}, int> =0 > stateless_lambda_t( Fin&& f ) { new ((void*)&data()) F( std::forward<Fin>(f) ); } stateless_lambda_t(stateless_lambda_t const&)=default; template<class...Args> decltype(auto) operator()(Args&&...args)const { return (*static_cast<F*>( (void*)&data() ))(std::forward<Args>(args)...); } stateless_lambda_t() = default; }; template<class F> stateless_lambda_t<std::decay_t<F>> make_stateless( F&& fin ) { return {std::forward<F>(fin)}; } 

Now we can:

auto t = make_stateless([]{ func(); }); 

and your code works.

A static_assert or SFINAE that the F is actually an empty type might be a good idea. You know, for quality.

The use of C++14 features can be replaced with manual decltype and spewing typename and ::type keywords. This answer was originally written for a C++14 question that was closed as a duplicate of this one.

live example.

1 Comment

I'm afraid I can't get this quite to work. Could you post a full code example?
7

We can assume that the lambda will always be empty, thus, we can just do a cast from another empty type, since they both have the same memory layout. So we build a wrapper class that makes a default constructible function object:

template<class F> struct wrapper { static_assert(std::is_empty<F>(), "Lambdas must be empty"); template<class... Ts> auto operator()(Ts&&... xs) const -> decltype(reinterpret_cast<const F&>(*this)(std::forward<Ts>(xs)...)) { return reinterpret_cast<const F&>(*this)(std::forward<Ts>(xs)...); } }; 

Now a static assert is added to make sure that the lambda is always empty. This should always be the case(since its required to decay to a function pointer), but the standard doesn’t explicitly guarantee it. So we use the assert to at least catch the insane implementation of lambdas. Then we just cast the wrapper class to the lambda since both of them are empty.

Finally the lambda could be constructed like this:

template <class F> void function_caller() { wrapper<F> f; f(); } 

2 Comments

Nice solution. Just a little modification: *reinterpret_cast<F*>(nullptr)(...) will cause Access Violation at runtime whenever F::operator() tries to dereference itself instead of silently corrupting memory after wrapper object. static_assert() assures us that 'F' has no fields, but... you never know what F does.
An access violation is not guaranteed for dereferencing a null pointer.
2

No.

However I believe that lambdas can be copied, so your functor_caller could take an argument to initialize its attribute.

Still, instead of reinventing the wheel, I would use std::function instead.

5 Comments

No. Example of using std::function within the context of my question.
@Andigor: I finally understood the issue. The body of the lambda is not part of its type. Therefore, default constructing a lambda from its type, even if it were possible, would not make sense. It's like default constructing void (*)(), all you get a is a null pointer to an hypothetic function that takes no parameter and returns nothing => there is nothing meaningful you can do with this null pointer! This is why you need to copy the existing lambda.
Thank you! I thought that the compiler generates simple functor when saw the lambda declaration and the body of lambda is in overloaded operator() Seems that I was wrong....
@Andigor: This is just a way for the Standard to describe how it interacts with the existing features of the language, as far as I understand.
std::function is damn slow compared to a raw lambda call
1

Prior to C++20 closure types are not default constructible and have no default constructor.

Since C++20 captureless lambdas are default constructible, i.e. they have a default constructor.

1 Comment

The question summarizes the changes better stackoverflow.com/questions/55708180/…

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.