Передача лямбда с списком захвата в качестве аргумента функции [duplicate]

Чтобы использовать методы и член объекта, вам сначала нужно создать этот объект. Если вы его не создали (переменная, которая должна содержать объект, не инициализируется), но вы пытаетесь использовать его методы или переменные, вы получите эту ошибку.

Иногда вы можете просто забыть инициализировать .

Отредактировано: new не может вернуть значение null, но исключение огня при ошибке. Давно это было на некоторых языках, но не больше. Спасибо @John Saunders за указание на это.

73
задан duncan 21 October 2011 в 17:00
поделиться

7 ответов

Поскольку захват лямбда должен сохранять состояние, на самом деле нет простого «обходного пути», поскольку они не просто обычные функции. Точка о указателе функции заключается в том, что она указывает на одну глобальную функцию, и эта информация не имеет места для состояния.

Ближайшее обходное решение (которое фактически отбрасывает состояние) означает предоставление некоторого типа глобальная переменная, доступ к которой осуществляется из вашей лямбда / функции. Например, вы можете создать традиционный объект-функтор и дать ему статическую функцию-член, которая ссылается на какой-то уникальный (глобальный / статический) экземпляр.

Но это своего рода победа цели цели захвата лямбда.

33
ответ дан Kerrek SB 26 August 2018 в 02:33
поделиться

Существует хакерский способ преобразования захватной лямбда в указатель функции, но вам нужно быть осторожным при ее использовании:

https://codereview.stackexchange.com/questions/ 79612 / c-ifying-a-capture-lambda

Тогда ваш код будет выглядеть следующим образом (предупреждение: компиляция мозга):

int main()
{

    vector<string> entries;

    auto const callback = cify<int(*)(const char *, const struct stat*,
        int)>([&](const char *fpath, const struct stat *sb,
        int typeflag) -> int {
        entries.push_back(fpath);
        return 0;
    });

    int ret = ftw("/etc", callback, 1);

    for (auto entry : entries ) {
        cout << entry << endl;
    }

    return ret;
}
0
ответ дан Community 26 August 2018 в 02:33
поделиться

Хе-хе - довольно старый вопрос, но все же ...

#include <iostream>
#include <vector>
#include <functional>

using namespace std;

// We dont try to outsmart the compiler...
template<typename T>
int ftw(const char *fpath, T callback) {
  return callback(fpath);
}

int main()
{
  vector<string> entries;

  // ... now the @ftw can accept lambda
  int ret = ftw("/etc", [&](const char *fpath) -> int {
    entries.push_back(fpath);
    return 0;
  });

  // ... and function object too 
  struct _ {
    static int lambda(vector<string>& entries, const char* fpath) {
      entries.push_back(fpath);
      return 0;
    }
  };
  ret = ftw("/tmp", bind(_::lambda, ref(entries), placeholders::_1));

  for (auto entry : entries ) {
    cout << entry << endl;
  }

  return ret;
}
3
ответ дан egorse 26 August 2018 в 02:33
поделиться

Лямбда-функции очень удобны и уменьшают код. В моем случае мне нужны лямбды для параллельного программирования. Но для этого требуются указатели захвата и функции. Мое решение здесь. Но будьте осторожны с объемом захваченных вами переменных.

template<typename Tret, typename T>
Tret lambda_ptr_exec(T* v) {
    return (Tret) (*v)();
}

template<typename Tret = void, typename Tfp = Tret(*)(void*), typename T>
Tfp lambda_ptr(T& v) {
    return (Tfp) lambda_ptr_exec<Tret, T>;
}

Пример

int a = 100;
auto b = [&]() { a += 1;};
void (*fp)(void*) = lambda_ptr(b);
fp(&b);

Пример с возвращаемым значением

int a = 100;
auto b = [&]() {return a;};
int (*fp)(void*) = lambda_ptr<int>(b);
fp(&b);
5
ответ дан Evgeny Karpov 26 August 2018 в 02:33
поделиться

Нашел ответ здесь: http://meh.schizofreni.co/programming/magic/2013/01/23/function-pointer-from-lambda.html

Он преобразует lambda pointer в void* и конвертирует обратно при необходимости.

  1. - void*: auto voidfunction = new decltype (to_function (lambda)) (to_function (lambda));
  2. из void*: автофункция = static_cast & lt; std :: function *> (voidfunction);
-1
ответ дан Ganesh Kamath - 'Code Frenzy' 26 August 2018 в 02:33
поделиться

Я просто столкнулся с этой проблемой.

Код компилируется отлично без лямбда-захватов, но есть ошибка преобразования типа с захватом лямбда.

Решение с C ++ 11 - использовать std::function (изменить: после этого примера показано другое решение, которое не требует изменения сигнатуры функции). Вы также можете использовать boost::function (который работает значительно быстрее). Пример кода - изменился так, чтобы он компилировался, скомпилирован с помощью gcc 4.7.1:

#include <iostream>
#include <vector>
#include <functional>

using namespace std;

int ftw(const char *fpath, std::function<int (const char *path)> callback) {
  return callback(fpath);
}

int main()
{
  vector<string> entries;

  std::function<int (const char *fpath)> callback = [&](const char *fpath) -> int {
    entries.push_back(fpath);
    return 0;
  };

  int ret = ftw("/etc", callback);

  for (auto entry : entries ) {
    cout << entry << endl;
  }

  return ret;
}

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

#include <iostream>
#include <vector>
#include <functional>

using namespace std;

// Original ftw function taking raw function pointer that cannot be modified
int ftw(const char *fpath, int(*callback)(const char *path)) {
  return callback(fpath);
}

static std::function<int(const char*path)> ftw_callback_function;

static int ftw_callback_helper(const char *path) {
  return ftw_callback_function(path);
}

// ftw overload accepting lambda function
static int ftw(const char *fpath, std::function<int(const char *path)> callback) {
  ftw_callback_function = callback;
  return ftw(fpath, ftw_callback_helper);
}

int main() {
  vector<string> entries;

  std::function<int (const char *fpath)> callback = [&](const char *fpath) -> int {
    entries.push_back(fpath);
    return 0;
  };
  int ret = ftw("/etc", callback);

  for (auto entry : entries ) {
    cout << entry << endl;
  }

  return ret;
}
41
ответ дан Jay West 26 August 2018 в 02:33
поделиться

Используя локально глобальный (статический) метод, это можно сделать следующим образом

template <class T>
auto wrap(T t) {
  static T fn = t;
  return [] { fn(); };
}

Предположим, что мы имеем

void some_c_func(void (*callback)());

. Таким образом, использование будет

some_c_func(wrap([&] {
  // code
}));

Это работает, потому что каждая лямбда имеет уникальную подпись, поэтому статичность не является проблемой. Следуя общей оболочке с переменным числом аргументов и любым типом возврата с использованием того же метода.

template <class T>
struct lambda_traits : lambda_traits<decltype(&T::operator())>
{ };

template <class T, class R, class... Args>
struct lambda_traits<R(T::*)(Args...) const> {
    typedef R (*pointer)(Args...);

    static pointer cify(T t) {
        static T fn = t;
        return [](Args... args) {
            return fn(args...);
        };
    }
};

template <class T>
inline typename lambda_traits<T>::pointer cify(T t) {
    return lambda_traits<T>::cify(t);
}

И аналогичное использование

void some_c_func(int (*callback)(some_struct*, float));

some_c_func(cify([&](some_struct* s, float f) {
    // making use of "s" and "f"
    return 0;
}));
3
ответ дан Vladimir Talybin 26 August 2018 в 02:33
поделиться
Другие вопросы по тегам:

Похожие вопросы: