randomThought
randomThought

Reputation: 6393

Overloading function template based on lambda arguments

I am trying to create a function where callers can pass in lambdas with a certain set of known parameters (the return type can be anything the caller wants) Let's say the possible lambda signatures are

  1. T (Widget*)
  2. T (Widget2*)

I've tried a couple things but I can't get any of them to work

struct Widget2{
    int count = 0;
};

class Widget {
public:
template<typename Fn, typename T = std::invoke_result_t<Fn, Widget*>>
T doIt(Fn&& fn)
{
    return fn(_sibling);
}

template<typename Fn, typename T = std::invoke_result_t<Fn, Widget2*>>
T doIt(Fn&& fn)
{
    return fn(_other);
}

private: 
Widget* _sibling = nullptr;
Widget2* _other = nullptr;
};

I've also tried doing something like this

template<typename Fn>
auto doIt(Fn&& fn)
{
    if (std::is_invocable_v<Fn, Widget*>)
        return fn(_sibling);
    else if (std::is_invocable_v<Fn, Widget2*>)
        return fn(_other);
}

this code in a compiler: https://wandbox.org/permlink/wMAuw5XXnc0zTjlk

I'd rather avoid having to add multiple functions like doItWidget1, doItWidget2 and so on.

Is there a way I can basically overload functions based on the arguments of the incoming lambda?

Upvotes: 0

Views: 53

Answers (1)

cigien
cigien

Reputation: 60238

You can use enable_if to sfinae away the wrong overload

template<typename Fn, std::enable_if_t<std::is_invocable_v<Fn, Widget*>, int> = 0>
auto doIt(Fn&& fn)
{
    return fn(_sibling);
}

template<typename Fn, std::enable_if_t<std::is_invocable_v<Fn, Widget2*>, int> = 0>
auto doIt(Fn&& fn)
{
    return fn(_other);
}

Note that you don't even need to figure out the return type T, you can just use auto to do that.

Here's a demo.

Upvotes: 1

Related Questions