Hi I have a problem, I hope you can help me with.

I have a number, which I need to compare to some values.

I do not wish to go through all the values, and compare them individually, as I there are too many for it to be efficient.

Neither do I want to create an array with the size of the range of numbers, as it can anything from 0 UINT_MAX

So I am hoping that you might have a better solution.

Here is an example of what I have tried, but didn't work,
because I get the values dynamicly

class Mother
{
public:
    Mother(){}
    ~Mother(){}

    template<int msg> inline void HandleMessage(){};
    
    template<> inline void HandleMessage<10>()
    {
        std::cout<<"It works!\n";
    }
};

Dani AI

Generated

Template specialization only works at compile time, so it cannot match message IDs that are discovered at runtime. As noted, searching (binary or otherwise) still costs time on every dispatch; for a GUI where widgets dynamically subscribe or unsubscribe (the situation described by and clarified after 's question), the usual pattern is a runtime publish/subscribe (message -> subscribers) registry. That way an incoming message touches only the list of widgets that registered interest in that specific message instead of scanning a huge domain or allocating a UINT_MAX-sized array.

A compact, practical implementation uses an unordered_map from message id to a container of handlers, with subscribe returning a small HandlerId that can be used to unsubscribe. Snapshotting the handler list before invoking callbacks avoids holding locks while user code runs and lets subscription changes during dispatch be handled safely.

#include <unordered_map>
#include <vector>
#include <functional>
#include <mutex>
#include <atomic>
#include <algorithm>

class MessageBus {
public:
    using Msg = uint32_t;
    using HandlerId = std::size_t;
    using Handler = std::function<void(Msg)>;

    HandlerId subscribe(Msg m, Handler h) {
        std::lock_guard<std::mutex> lk(mutex_);
        HandlerId id = ++nextId_;
        listeners_[m].emplace_back(id, std::move(h));
        return id;
    }

    void unsubscribe(Msg m, HandlerId id) {
        std::lock_guard<std::mutex> lk(mutex_);
        auto it = listeners_.find(m);
        if (it == listeners_.end()) return;
        auto &vec = it->second;
        vec.erase(std::remove_if(vec.begin(), vec.end(),
                 [id](auto &p){ return p.first == id; }), vec.end());
        if (vec.empty()) listeners_.erase(it);
    }

    void publish(Msg m) {
        std::vector<Handler> snapshot;
        {
            std::lock_guard<std::mutex> lk(mutex_);
            auto it = listeners_.find(m);
            if (it == listeners_.end()) return;
            for (auto &p : it->second) snapshot.push_back(p.second);
        }
        for (auto &h : snapshot) h(m);
    }

private:
    std::unordered_map<Msg, std::vector<std::pair<HandlerId, Handler>>> listeners_;
    std::mutex mutex_;
    std::atomic<HandlerId> nextId_{0};
};

Notes and trade-offs: store handlers as lambdas that capture a weak_ptr to the widget so callbacks do not dereference destroyed objects (e.g., subscribe(..., [w = std::weak_ptr<Widget>(wp)](Msg m){ if (auto s = w.lock()) s->onMessage(m); })). Protect subscribe/unsubscribe with a mutex; avoid holding that lock while calling handlers by using the snapshot technique above. If the message id space is small and dense, a bitset or indexed vector can beat a map, but for large sparse ranges the map-of-subscriber-lists is usually the best balance of speed and memory.

Recommended Answers

All 6 Replies

Hi I have a problem, I hope you can help me with.

I have a number, which I need to compare to some values.

I do not wish to go through all the values, and compare them individually, as I there are too many for it to be efficient.

Neither do I want to create an array with the size of the range of numbers, as it can anything from 0 UINT_MAX

So I am hoping that you might have a better solution.

Here is an example of what I have tried, but didn't work,
because I get the values dynamicly

class Mother
{
public:
    Mother(){}
    ~Mother(){}

    template<int msg> inline void HandleMessage(){};
    
    template<> inline void HandleMessage<10>()
    {
        std::cout<<"It works!\n";
    }
};

I think you'll have to be a bit more specific about what you're after, what needs to be compared, stuff like that. I don't know what to make of the code snippet, as it has no comparisons. off the top of my head, if you have ordered data, use a binary search so you don't have to compare every element, but again, without having any idea what kind of data you have or what kind of comparisons you need to make, it's hard to speculate.

Well it is an integer, compared to a list of integers.

Well it is an integer, compared to a list of integers.

Any reason a binary search won't work?

Too time consuming. I would rather not do it at all then

And about the code snippet, if I create an instance of Mother,
and call HandleMessage<10> it would print "It works!\n".

But if I call it with any other value it would do nothing,
the reason I am not doing this, is that I don't know the values at compile time.

Too time consuming. I would rather not do it at all then

And about the code snippet, if I create an instance of Mother,
and call HandleMessage<10> it would print "It works!\n".

But if I call it with any other value it would do nothing,
the reason I am not doing this, is that I don't know the values at compile time.

Care to give a little more background?

Ok I am building a GUI Framework, where there is a Widget class,
which can both have mother widgets and be a mother widget.

When some event happens, the widget receives a message, in the form of an integer value(win32).
I want the widgets to be able to say to their children "I want to know when this happens", and then the mother widget's mother to be able do the same.

The alternative to this subscribe behavior, is to send some of the messages to the widget's mother

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.