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

Я хотел бы передать функции в метод универсального класса, чтобы универсальный класс мог вызывать функции, не требующие аргументов, одного аргумента, двух аргументов и т. Д.

Я видел различные шаблоны, но мне не нравится синтаксис. Предыдущий вопрос SO рекомендовал передавать лямбда-выражения, оборачивая функцию:

/questions/30664567/kak-peredat-stdfunction-s-raznyimi-parametrami-v-odnu-i-tu-zhe-funktsiyu/30664571#30664571

где ответ:

void run_callback(std::function<void()>& func) 
{
    func();
}

run_callback([]{ func_without_params(); });

и поэтому я добавил метод, который не требует аргументов:

void func_without_params()
{
    std::cout << "x" << std::endl;
}

но когда я звоню:

run_callback([]{ func_without_params(); });

в VS2013 intellisense обнаруживает ошибку, и я получаю ошибку компилятора:

error C2664: 'void run_callback(std::function<void (void)> &)' :
cannot convert argument 1 from
'main::<lambda_de925f4d5cd926a8bb664f9c057a7a19>' to
'std::function<void (void)> &'

Что такое main::<lambda_de925f4d5cd926a8bb664f9c057a7a19> тип? Я не до конца понимаю ошибку.

2 ответа

Решение

За исключением злых расширений компилятора, вы не можете инициализировать неконстантную ссылку (параметр func) с чем-то, что не является l-значением. Сделайте параметр const:

#include <functional>
#include <iostream>

void run_callback(std::function<void()> const &func)
{
    func();
}

void func_without_params()
{
    std::cout << "x" << std::endl;
}

int main()
{
    run_callback([] { func_without_params(); });
}

Что такое main::<lambda_de925f4d5cd926a8bb664f9c057a7a19> тип?

Что ссылки говорят о лямбда-выражении:

Лямбда-выражение является выражением prvalue уникального неименованного неагрегированного неагрегированного типа класса, известного как тип закрытия, который объявляется в наименьшей области блока, области класса или области пространства имен, содержащей лямбда-выражение.

безымянный только для программистов, компилятор знает это имя и в вашем случае lambda_de925f4d5cd926a8bb664f9c057a7a19 это имя типа закрытия. main относится к функции, внутри которой был определен тип замыкания.

Вы можете использовать https://cppinsights.io/, чтобы заглянуть за кулисы. cppinsights использует Clang, который не принимает привязку Rvalue к ссылке Lvalue, поэтому измените код на:

void run_callback(std::function<void()> func) // take by value

и вывод из cppinsights:

int main() { // scope of closure type

  class __lambda_14_16 { // closure type
    public: inline /*constexpr */ void operator()() const
    {
      func_without_params();
    }

  };

  run_callback(std::function<void ()>(__lambda_14_16{}));
}
Другие вопросы по тегам