简体   繁体   中英

any visitor doesn't work with member function

I've implemented a simple any class and an appropriate visitor class. This works great on function level. But when I try to use the visitor as a member within a class the registered member function is found, called but not entered.

That's a strange behavior that I don't understand.
I tried it with gcc 5 and 6.
You will find my code below and here online.

The program should increment an integer value.

#include <iostream>
#include <functional>
#include <typeindex>
#include <unordered_map>

// simple any class
struct any {
    ~any() { if(val) { deleter_(val); } }
    template < class T >
    any(const T &v)
        : val(new T(v))
        , deleter_(&destroy<T>)
        , indexer_(&index<T>)
    {}

    typedef void (*deleter)(void*);
    typedef std::type_index (*indexer)();

    template <typename T>
    static void destroy(void *p) { delete (T*)p; }
    template < class T >
    static std::type_index index() { return std::type_index(typeid(T)); }

    template < class T >
    T& as() { return *static_cast<T*>(val); }

    std::type_index type_index() const { return indexer_(); }

    void *val = nullptr;
    deleter deleter_ = nullptr;
    indexer indexer_ = nullptr;

};

struct any_visitor {
    using function = std::function<void(any&)>;

    template <typename T>
    void register_visitor(const std::function<void(T&)> &f) {
        fs.insert(std::make_pair(
          std::type_index(typeid(T)),
          function([&f](any & x) {
            f(x.as<T>());
          })
        ));
    }

    void visit(any & x) {
        auto it = fs.find(x.type_index());
        if (it != fs.end()) {
            it->second(x);
        }
    }

    std::unordered_map<std::type_index, function> fs;
};

struct processor  {
    // visitor as class member
    any_visitor visitor;

    processor() {
        // register member function
        visitor.register_visitor<int>([this](int &i) { this->process(i); });
    }

    void apply(any &a) { visitor.visit(a); }

    void process(int &val) { ++val; }
};

int main()
{
    any ai = 7;
    any aii = 10;

    // visitor inside a function
    any_visitor visitor;
    visitor.register_visitor<int>([](int &val) {
        ++val;
    });
    // increment works
    std::cout << "function before: " << aii.as<int>() << "\n";
    visitor.visit(aii);
    std::cout << "function after: " << aii.as<int>() << "\n";

    // increment doesn't work
    std::cout << "class before: " << ai.as<int>() << "\n";
    processor p;
    p.apply(ai);
    std::cout << "class after: " << ai.as<int>() << "\n";

    return 0;
}

You're storing a reference to a temporary, with all that entails of undefined behaviour.
The lambda function in register_visitor needs to capture f by value.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM