Создание C ++ лямбда по типу

Я хочу способ сделать функтор из функции. Теперь я пытаюсь обернуть вызов функции лямбда-функцией и создать ее позже. Но компилятор говорит, что лямбда-конструктор удален. Так есть ли способ скомпилировать этот код? Или может быть другой способ для этого?

#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;
}

Теперь я получаю такую ошибку компилятора:

error: use of deleted function  '<lambda()>::<lambda>()'

error: a lambda closure type has a deleted default constructor

На мой взгляд, единственный способ - использовать макрос:

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

затем

WRAP_FUNC(func);

а затем (в основном)

functor_caller<func_functor>()
 Nawaz17 июн. 2012 г., 18:51
@ user315052: Это на самом деле та же проблема.
 andigor18 июн. 2012 г., 09:52
Нет, я не хочу его использовать. Я пытаюсь получить тип лямбда и затем построить его по умолчанию.
 jxh17 июн. 2012 г., 18:50
Я даже не могу объявить переменную типаfunctor_type вmain, Нужно заставить это работать сначала.
 MSalters18 июн. 2012 г., 08:59
Ты пробовалF f(t); ? В настоящее время,functor_caller не знает оt.
 MSalters18 июн. 2012 г., 12:03
@Andigor: Это не имеет смысла. Для лямбда-типов нет значения по умолчанию. Компилятор говорит вам об этом (нет ctor по умолчанию).

Ответы на вопрос(4)

Мы можем предположить, что лямбда всегда будет пустой, поэтому мы можем просто выполнить приведение из другого пустого типа, поскольку они оба имеют одинаковую структуру памяти. Итак, мы создаем класс-оболочку, которая делает объект по умолчанию конструируемой функцией:

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)...);
    }
};

Теперь добавлено статическое утверждение, чтобы лямбда всегда была пустой. Это всегда должно иметь место (поскольку требуется распад на указатель на функцию), но стандарт явно не гарантирует этого. Таким образом, мы используем assert, чтобы хотя бы поймать безумную реализацию лямбд. Затем мы просто приводим класс-обертку к лямбде, поскольку они оба пусты.

Наконец лямбда может быть построена так:

template <class F>
void function_caller()
{
    wrapper<F> f;
    f();
}
 13 июл. 2015 г., 20:07
Нарушение доступа не гарантируется для разыменования нулевого указателя.
 10 мар. 2015 г., 02:57
Хорошее решение. Просто небольшая модификация:*reinterpret_cast<F*>(nullptr)(...) будет вызывать нарушение прав доступа во время выполнения всякий раз, когдаF::operator() пытается разыскивать себя вместо того, чтобы молча портить память послеwrapper объект.static_assert() уверяет нас, что «F»; не имеет полей, но ... вы никогда не знаете, чтоF делает.

что у вас есть лямбда захвата, подобная этой:

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

Что это может означать для создания объекта по умолчаниюdecltype(t)?

Как подсказывает @Matthieu, вы можете обернуть лямбду вfunction объект:

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

Или вы можете создать шаблон вашего call-сайта непосредственно по типу лямбды (или любой вызываемой сущности):

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

Использование:int a = 0; for (int i : { 1, 3, 5 }) { a += compute(10, i, t); }

Если это вообще возможно, второй стиль предпочтительнее, так как преобразование вstd::function является нетривиальной, потенциально дорогой операцией, как и фактический вызов функции через полученный объект. Однако, если вам нужно хранить однородную коллекцию разнородных вызываемых объектов, тоstd::function вполне может быть самым простым и удобным решением.

 andigor17 июн. 2012 г., 22:11
Теоретически построение лямбды по умолчанию в вашем примере означает, что я получаю ссылку наn который может быть ссылкой, если этот объект был разрушен. Но еслиn живет у меня правильная ссылка.
 andigor17 июн. 2012 г., 22:19
Но мой вопрос был о создании функтора из функции во время компиляции ...
 17 июн. 2012 г., 22:34
@Andigor: если вы используете стиль шаблона, вам даже не нужно создавать промежуточный функтор - вы можете просто передать функцию (указатель) напрямую ... и заметить, чтоn не обязательно в области видимости и не является значимой частью типа.

Лямбды не имеют конструкторов по умолчанию. Когда-либо. Единственные конструкторы, к которым они иногда предоставляют доступ, - это (в зависимости от того, что они захватывают) конструкторы копирования и / или перемещения.

Если вы создадите функтор без общедоступного конструктора по умолчанию, вы получите ту же ошибку.

В C ++ 17 вы можете решить это сconstexpr лямбда иoperator+ распад на указатель на функцию. Тип, который несет указатель на функцию и вызывает ее легко сauto параметры шаблона.

В C ++ 11 ты должен быть немного хакерским.

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)};
}

Теперь мы можем:

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

и твой код работает.

static_assert или сфина что тоF на самом деле пустой тип может быть хорошей идеей. Вы знаете, для качества.

Использование функций C ++ 14 можно заменить ручнымdecltype и извергатьtypename а также::type ключевые слова. Этот ответ был первоначально написан для вопроса C ++ 14, который был закрыт как дубликат этого.

живой пример.

 29 сент. 2016 г., 15:40
Исправлены ошибки компиляции @Knarf, опубликован живой пример.
 29 сент. 2016 г., 15:47
Это сработало! Спасибо!
 29 сент. 2016 г., 15:14
Боюсь, я не могу заставить это работать. Не могли бы вы опубликовать полный пример кода?

Нет.

Однако я считаю, что лямбды можно копировать, поэтому вашиfunctor_caller может принять аргумент для инициализации своего атрибута.

Тем не менее, вместо того, чтобы изобретать велосипед, я бы использовалstd::function вместо.

 andigor18 июн. 2012 г., 10:07
У вас есть какая-либо четкая информация об этом?
 andigor17 июн. 2012 г., 19:38
Можете ли вы показать пример использования std :: function?
 andigor17 июн. 2012 г., 21:51
Нет. Пример использования std :: function в контексте моего вопроса.
 andigor18 июн. 2012 г., 09:49
Спасибо! Я думал, что компилятор генерирует простой функтор, когда увидел лямбда-объявление и тело лямбды находится в перегруженномoperator() Кажется, я был не прав ....
 18 июн. 2012 г., 08:13
@Andigor: я наконец понял проблему.body лямбда не является частью его типа. Поэтому построение лямбды по типу по умолчанию, даже если бы это было возможно, не имело бы смысла. Это похоже на конструкцию по умолчаниюvoid (*)()все, что вы получаете - это нулевой указатель на гипотетическую функцию, которая не принимает параметров и ничего не возвращает = & gt; нет ничего значимого, что вы можете сделать с этим нулевым указателем! Вот почему вам нужноcopy существующая лямбда.

Ваш ответ на вопрос