Search code examples
c++c++11lambdaanonymous-classfirst-class-functions

Can I create an anonymous on-the-fly class (implementation of an interface) in C++


In C++, can I create an implementation of an interface on the fly (which ideally binds local-scope variables.) Not sure how to explain it better, so I will put down what I would like the code to look like (roughly):

// Given the following:

class Visitor
{
    virtual void visit(const Data& data) = 0;
}

class DataStore
{
    void visitData(Visitor& visitor) { /** Invokes visitor with each item of data. */ }
}

// Imagine one would write something like:

void inSomeFunction(DataStore& store)
{
    std::string myName = "bob";

    class MyVisitor: public Visitor
    {
    public:
        MyVisitor(const std::string& p): person(p);
        virtual void visit(const Data& data) override
        {
            std::cout << person << " is visiting " << data << std::endl;
        }
    private:
        std::string person;
    }

    MyVisitor myVisitor(myName);
    store.visitData(myVisitor);
}

// Instead of the above, I want to write instead something like:

void inSomeFunction(DataStore& store)
{
    std::string myName = "bob";

    store.visitData(
        class: public MyVisitor
        {
            virtual void visit(const Data& data) override
            {
                std::cout << myName << " is visiting " << data << std::endl;
            }
        }
    );
}

I realise that I'm asking 2 questions here - can you create an anonymouse class like this, and can you bind variables from the local scope (like I've referred to myName). But I need both for it to be useful.

If the above can't be done, what's the closest one can get to using say C++11 lambdas or similar, in terms of conciseness / lack of boilerplate.


Solution

  • If you have to have an interface, then you should do what Kerrek suggested.

    But even better would be to change your interface from:

    class DataStore
    {
        void visitData(Visitor& visitor) { 
            // bunch of calls to visitor.visit(...) ... 
        }
    }
    

    to:

        template <class Visitor>
        void visitData(Visitor visitor) { 
            // bunch of calls to visitor(...) ... 
        }
    

    This would allow you to simply write:

    std::string myName = "bob";
    store.visit([myName](const Data& data) {
        std::cout << myName << " is visiting " << data << std::endl;
    });
    

    which is far more natural in my opinion. If the interface of DataStore is outside of your control, then this answer is totally moot.