Overload depending on lambda result

I have a class like:

class foo
{
    EventManager<LRESULT(UINT, WPARAM, LPARAM)> Events;

    template<typename T>
    void addListener(int e, T&& lambda) { events.add(e, lambda); }
};

      

However, I need to accept two types of lambda. One with signature:

[&](UINT, WPARAM, LPARAM) -> LRESULT {}

and one with the signature: [&](UINT, WPARAM, LPARAM) -> void {}

.

So, I want to define the return type of lambdas ..

I've tried something like:

template<typename T>
void addListener(int e, T&& listener)
{
    if (std::is_void<decltype(listener(0, 0, 0))>::value)
    {
        Events.Subscribe(e, [&](UINT msg, WPARAM wp, LPARAM lp) -> LRESULT {
            listener(msg, wp, lp);
            return DefWindowProcW(this->Handle(), msg, wp, lp);
        });
    }

    Events.Subscribe(e, [&](UINT msg, WPARAM wp, LPARAM lp) -> LRESULT {
        std::function<LRESULT()> func = std::bind(listener, msg, wp, lp);
        return func();
    });
}

      

I also tried to declare the function as a template with the following signature:

template<typename T, typename = typename std::enable_if<std::is_void<typename std::result_of<T(UINT, WPARAM, LPARAM)>::type>::value>::type>

to overload it, but it doesn't work.

Any ideas what I can do without creating two methods (one for each signature)?

+3


source to share


1 answer


Option number 1

Send the call to the correct overload:

#include <functional>
#include <type_traits>
#include <utility>

class foo
{
public:
    template <typename T>
    void addListener(int e, T&& listener)
    {
        addListener(e, std::forward<T>(listener), std::is_void<decltype(listener(0, 0, 0))>{});
    }

private:
    EventManager<LRESULT(UINT, WPARAM, LPARAM)> Events;

    template <typename T>
    void addListener(int e, T&& listener, std::true_type)
    {
        Events.Subscribe(e, [=](UINT msg, WPARAM wp, LPARAM lp) -> LRESULT {
            listener(msg, wp, lp);
            return DefWindowProcW(this->Handle(), msg, wp, lp);
        });
    }

    template <typename T>
    void addListener(int e, T&& listener, std::false_type)
    {
        Events.Subscribe(e, [=](UINT msg, WPARAM wp, LPARAM lp) -> LRESULT {
            std::function<LRESULT()> func = std::bind(listener, msg, wp, lp);
            return func();
        });
    }
};

      

DEMO 1

Option number 2

Add conditional overloads SFINAE (you need a dummy type template parameter typename = void

if you want to hide enable_if

in the template parameter list in the second overload to make function template declarations great):



#include <functional>
#include <type_traits>

class foo
{
public:    
    template <typename T,
              typename = typename std::enable_if<std::is_void<typename std::result_of<T(UINT, WPARAM, LPARAM)>::type>::value>::type>
    void addListener(int e, T&& listener)
    {
        Events.Subscribe(e, [=](UINT msg, WPARAM wp, LPARAM lp) -> LRESULT {
            listener(msg, wp, lp);
            return DefWindowProcW(this->Handle(), msg, wp, lp);
        });
    }

    template <typename T,
              typename = typename std::enable_if<!std::is_void<typename std::result_of<T(UINT, WPARAM, LPARAM)>::type>::value>::type,
              typename = void>
    void addListener(int e, T&& listener)
    {
        Events.Subscribe(e, [=](UINT msg, WPARAM wp, LPARAM lp) -> LRESULT {
            std::function<LRESULT()> func = std::bind(listener, msg, wp, lp);
            return func();
        });
    }

private:
    EventManager<LRESULT(UINT, WPARAM, LPARAM)> Events;
};

      

DEMO 2

Option number 3

Use a return type with a qualifier decltype()

to enable / disable overloading:

#include <functional>
#include <type_traits>
#include <utility>

class foo
{
public:    
    template <typename T>
    auto addListener(int e, T&& listener)
        -> typename std::enable_if<std::is_void<decltype(std::forward<T>(listener)(0, 0, 0))>{}>::type
    {
        Events.Subscribe(e, [=](UINT msg, WPARAM wp, LPARAM lp) -> LRESULT {
            listener(msg, wp, lp);
            return DefWindowProcW(this->Handle(), msg, wp, lp);
        });
    }

    template <typename T>
    auto addListener(int e, T&& listener)
        -> typename std::enable_if<!std::is_void<decltype(std::forward<T>(listener)(0, 0, 0))>{}>::type
    {
        Events.Subscribe(e, [=](UINT msg, WPARAM wp, LPARAM lp) -> LRESULT {
            std::function<LRESULT()> func = std::bind(listener, msg, wp, lp);
            return func();
        });
    }

private:
    EventManager<LRESULT(UINT, WPARAM, LPARAM)> Events;
};

      

DEMO 3

+5


source







All Articles