locked
Adding a lambda capture breaks build

    Question

  • I have a functor "SceneNodeWalk" below, which is used in the start of a DeleteTree function.

    The call to SceneNodeWalk::operator() in DeleteTree with an empty lambda capture iterates the tree fine, and every node is hit.

    Now, I want to use the "nodes" vector in the second set of code.  If I change the lambda introducer to [=], or [&], or anything other than [], the compiler complains that SceneNodeWalk::operator() cannot be called with the given argument list.

    Any clues on how to make the capture work?  Is it a problem with my definition of the functor?

    class SceneNodeWalk

    {

    public:

    SceneNodeWalk(SceneNode* walkStartNode);

           SceneNode* operator()(void (*nodeFunction)(SceneNode* node, WalkParams &walkParams));

    private:

           SceneNode* m_WalkRootNode;

    };

    void SceneNode::DeleteTree(SceneNode* rootNode)

    {

           std::vector<SceneNode*> nodes;

           SceneNodeWalk walkItor(rootNode);

           walkItor([] (SceneNode* node, WalkParams& walkParams)

           {

                  //nodes.push_back(node);

           });

    }


    Jim Tomasko

    Wednesday, August 01, 2012 11:54 PM

Answers

  • Only a lambda which has no captures is directly convertible to a function pointer.  When you capture something, conceptually, you can think of it something like this:

    class MyFunctor
    {
    public:
    
        MyFunctor(SceneNode *captureThis) :
            _this(captureThis)
        {
        }
    
        void operator()(SceneNode * node, WalkParams& walkParams)
        {
            _this->nodes.push_back(node);
        }
    
    private:
    
        SceneNode *_this;
    };

    Here, you wouldn't expect to be able to convert MyFunctor::operator() to a raw function pointer as declared ( void(*)(SceneNode*, WalkParams&) ).  It's the same thing with the lambda.

    If you want the function to be able to take such, you can declare it in several ways:

    //
    // template:
    //
    // FUNC satisfies: void operator(SceneNode*, WalkParams&)
    template<typename FUNC>
    void operator()(const FUNC& func)
    {
       ...
    }
    
    //
    // std::function:
    //
    void operator()(std::function<void(SceneNode*, WalkParams&)> func)
    {
        ...
    }

     

    • Marked as answer by James Tomasko Thursday, August 02, 2012 4:47 PM
    Thursday, August 02, 2012 4:44 PM

All replies

  • I get a clean compile, but an intellisense error. The compiler always wins any conflicts.
    Thursday, August 02, 2012 12:06 AM
    Moderator
  • Ok, I'll go with the intellisense error, but if I ignore it, I can compile, but then if I add anything in the lambda introducing I can not compile.  I have tried [=], [nodes], and even [&] (with small rework)... no matter what I do, my original code will not compile if I uncomment the "nodes.push_back(node)" line, and attempt to pass in "nodes".

    Original question still stands.


    Jim Tomasko

    Thursday, August 02, 2012 1:32 AM
  • Only a lambda which has no captures is directly convertible to a function pointer.  When you capture something, conceptually, you can think of it something like this:

    class MyFunctor
    {
    public:
    
        MyFunctor(SceneNode *captureThis) :
            _this(captureThis)
        {
        }
    
        void operator()(SceneNode * node, WalkParams& walkParams)
        {
            _this->nodes.push_back(node);
        }
    
    private:
    
        SceneNode *_this;
    };

    Here, you wouldn't expect to be able to convert MyFunctor::operator() to a raw function pointer as declared ( void(*)(SceneNode*, WalkParams&) ).  It's the same thing with the lambda.

    If you want the function to be able to take such, you can declare it in several ways:

    //
    // template:
    //
    // FUNC satisfies: void operator(SceneNode*, WalkParams&)
    template<typename FUNC>
    void operator()(const FUNC& func)
    {
       ...
    }
    
    //
    // std::function:
    //
    void operator()(std::function<void(SceneNode*, WalkParams&)> func)
    {
        ...
    }

     

    • Marked as answer by James Tomasko Thursday, August 02, 2012 4:47 PM
    Thursday, August 02, 2012 4:44 PM