Quentamia
Quentamia

Reputation: 3292

Take generic lambda return type into consideration for SFINAE

I'd like to have a function that takes a generic lambda, but I need slightly different logic based on the lambda's return type. For example, I'd like to do something like the following (this is a contrived example):

template<typename F>
void foo(F &&function) {
    auto result = function();
    // Have different behavior based on `result`'s type.
}

To facilitate this, I thought I could use SFINAE. In my mind, this would look something like:

template<typename F,
         typename std::enable_if_t<???>>
void foo(F &&function) {

}

Does anyone know how I can enable/disable a method based on the return type of F?

Upvotes: 0

Views: 127

Answers (1)

cigien
cigien

Reputation: 60402

You don't need SFINAE for this. As mentioned in a comment, you could just write the different logic based on the return type in different overloads, and call that overload set

void f(int); // do the logic for an int
void f(double); // do the logic for a double
// ... and so on

template<typename F>
void foo(F &&function) 
{
    auto result = function();
    f(result); // get different behavior based on `result`'s type.
}

If the logic needs some data other than the return value, you'll need to pass that to the helper f.


To avoid that, and have all the logic in one place, you could write a compile time "switch" on the type of the return value

template<typename F>
void foo(F &&function) 
{
    auto result = function();
    if constexpr (std::is_same_v<decltype(result), int>)
      // logic for an int
    else if constexpr (std::is_same_v<decltype(result), double>)
      // logic for a double
    else
      // ... and so on
}

Note that these two options are not exactly equivalent, i.e. overload resolution may not behave exactly the same as is_same in all cases, due to factors like implicit conversions, etc. so you have to be a bit careful there. One fix would be to write an overload for the first version that catches everything other than exact conversions

template<typename T>
void f(T) = delete;

and this will be much closer to the second version.

Upvotes: 3

Related Questions