C++ захват переменной из лямбда функции

123
28 сентября 2019, 17:40

есть такая функция, которая принимает другую функцию:

GLvoid Graphics::SceneGraph::Node::childrenForEach(GLvoid(*callback)(Node* child)) noexcept
{
    Node* iterator = mChild;
    while (iterator) 
    {
        callback(iterator);
        iterator = iterator->mNextNode;
    }
}

Хочу вызвать ее следующим образом:

Tools::ShaderProgram& shader = mShaderManager.getShader(BASE_SHADER);
shader.use();
if (mRootNode->isExistChildren()) 
{
    mRootNode->childrenForEach([&shader](Node* child)
    {
        if (child->isExistMesh()) 
        {
            shader.setUniformMatrix("modelMatrix", child->getTransformation());
            child->getMesh().draw();
        }
    });
}

Но получаю следующую ошибку:

E0413   no suitable conversion function from "lambda []void (Graphics::SceneGraph::Node *child)->void" to "GLvoid (*)(Graphics::SceneGraph::Node *child)"

Что можно придумать, чтобы исправить это?

Answer 1
GLvoid Graphics::SceneGraph::Node::childrenForEach(GLvoid(*callback)(Node* child)) noexcept
{
    Node* iterator = mChild;
    while (iterator) 
    {
        callback(iterator);
        iterator = iterator->mNextNode;
    }
}

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

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

Самый лучшим вариантом, будет изменить сигнатуру функции childrenForEach на:

GLvoid Graphics::SceneGraph::Node::childrenForEach(std::function<GLvoid(Node *)> callback)) noexcept
{
    Node* iterator = mChild;
    while (iterator) 
    {
        callback(iterator);
        iterator = iterator->mNextNode;
    }
}

Если это невозможно, то отказаться от захвата переменных в лямбду и искать другие пути для доступа к shader:

mRootNode->childrenForEach([](Node* child)
{
    if (child->isExistMesh()) 
    {
        //shader.setUniformMatrix("modelMatrix", child->getTransformation());
        child->getMesh().draw();
    }
});     

Возможно вообще отказаться от использования функции childrenForEach и самому организовать обход элементов.

Дополнено: По поводу других способов доступа к переменной: без описания типа Graphics::SceneGraph::Node сложно что-то сказать, но скорее всего там есть методы для прохода по всем дочерним элементам без колбек функций. Другим способом будет сделать переменную shader но я бы не назвал это хорошим решением. Дайте ссылку где почитать про Graphics::SceneGraph::Node и тогда будет проще помочь.

Answer 2

Если вы хотите иметь возможность передавать лямбды с захватом, то придется либо делать childrenForEach шаблонной

template <typename F>
GLvoid Graphics::SceneGraph::Node::childrenForEach(F callback) noexcept
{
  ...
}

(и соответствующим образом подправить объявление в классе).

Либо использовать std::function

GLvoid Graphics::SceneGraph::Node::childrenForEach(std::function<GLvoid(Node*)>) noexcept
{
  ...
}

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

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

READ ALSO
динамический массив с++ [закрыт]

динамический массив с++ [закрыт]

Задача написать функцию на С++,переводящую число X из 10 системы счисления в 3

134
&ldquo;Thunk&rdquo; в контексте виртуальных функций

“Thunk” в контексте виртуальных функций

Что такое "Thunk" в контексте виртуальных функций?(Как работает?)

102
С++. Указатели. Операция delete

С++. Указатели. Операция delete

Я начинающий в программированииЧитая книгу о С++ в главе посвященной указателям (в частности оператору delete), я наткнулся на то, что в среде...

122
Как по очереди анимировать Views

Как по очереди анимировать Views

У меня на странице несколько ViewНужно чтобы каждый анимировался после предыдущей

118