Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get forwarded type from the template type and not the argument

Consider the following function:

template <class T>
constexpr /* something */ f(T&& x) {
    // do something
}

and let's say that I want to do sfinae based on the type of a forwarded argument passed to a function called myfunction. One way to achieve this is:

template <class T>
constexpr auto f(T&& x) -> decltype(myfunction(std::forward<T>(x))) {
    // do something
}

instead of doing this, is there a way to do it at the template level:

// This code won't compile
template <class T, class R = decltype(myfunction(std::forward<T>(x)))>
constexpr R f(T&& x) {
    // do something
}

except that I don't have access to x yet so this code won't compile. Is there a way to achieve this only based on T (possibly using std::declval)?

Note: this is not an X/Y problem, it's just an example to illustrate where this situation happen: I don't know how to do SFINAE with forwarding without accessing the variable because for me the behavior of std::forward is still a little mysterious.

like image 616
Vincent Avatar asked Mar 12 '17 06:03

Vincent


1 Answers

Yes, std::declval is indeed the key:

template <class T, class R = decltype(myfunction(std::declval<T>()))>
constexpr R f(T&& x) {
    // do something
}

This will either SFINAE out or R will be the return type of whichever overload of myfunction is chosen.

Your question makes it appear to me that you need a refresher on how reference-collapsing works; I suggest reading up in that area (this seems like a good starting point).

like image 64
ildjarn Avatar answered Nov 15 '22 01:11

ildjarn