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>()
Griwes
  • 8,805
  • 2
  • 43
  • 70
andigor
  • 722
  • 6
  • 17
  • I cannot even declare a variable of type `functor_type` in `main`. Need to get that to work first. – jxh Jun 17 '12 at 16:50
  • 1
    @user315052: That is actually the same problem. – Nawaz Jun 17 '12 at 16:51
  • Did you try `F f(t);` ? Currently, `functor_caller` doesn't know about `t`. – MSalters Jun 18 '12 at 06:59
  • No. I don't want to use it. I try get type of lambda and than default construct it. – andigor Jun 18 '12 at 07:52
  • @Andigor: That doesn't make sense. There's no default value for lambda types. The compiler tells you as much (no default ctor). – MSalters Jun 18 '12 at 10:03
  • Thank you. I also read the complier output. The main keywords of question were why and how. And I already have answer by Matthieu M. – andigor Jun 18 '12 at 11:46

5 Answers5

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.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • 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 Jun 17 '12 at 20:11
  • @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. – Kerrek SB Jun 17 '12 at 20:34
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.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
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();
}
Paul Fultz II
  • 17,682
  • 13
  • 62
  • 59
  • Nice solution. Just a little modification: `*reinterpret_cast(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. – Mykola Bohdiuk Mar 10 '15 at 01:57
  • An access violation is not guaranteed for dereferencing a null pointer. – Paul Fultz II Jul 13 '15 at 18:07
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.

Matthieu M.
  • 287,565
  • 48
  • 449
  • 722
  • No. Example of using std::function within the context of my question. – andigor Jun 17 '12 at 19:51
  • 3
    @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. – Matthieu M. Jun 18 '12 at 06:13
  • 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 Jun 18 '12 at 07:49
  • @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. – Matthieu M. Jun 18 '12 at 08:16
  • std::function is damn slow compared to a raw lambda call – Jean-Bernard Jansen May 19 '16 at 16:33
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.

  • The question summarizes the changes better https://stackoverflow.com/questions/55708180/lambda-closure-type-constructors – ghostcore07 Nov 16 '22 at 02:14