I\'m writing a network library and use move semantics heavily to handle ownership for file descriptors. One of my class wishes to receive file descriptor wrappers of other k
Unfortunately, it seems like trying out is_rvalue_reference (where TF is the perfectly-forwarded type) does not work well if you are actually trying to make overloads that distinguish between const T& and T&& (e.g. using enable_if in both, one with is_rvalue_reference_v and the other with !is_rvalue_reference_V).
A solution (albeit hacky) is to decay the forwarded T, then place the overloads in a container aware of these types. Generated this example:
Hup, I was wrong, just forgot to look at Toby's answer (is_rvalue_reference) -- though it's confusing that you can do std::forward, but I guess that's why decltype(arg) also works.
Anywho, here's what I used for debugging: (1) using struct overloads, (2) using the wrong check for is_rvalue_reference, and (3) the correct check:
/*
Output:
const T& (struct)
const T& (sfinae)
const T& (sfinae bad)
---
const T& (struct)
const T& (sfinae)
const T& (sfinae bad)
---
T&& (struct)
T&& (sfinae)
const T& (sfinae bad)
---
T&& (struct)
T&& (sfinae)
const T& (sfinae bad)
---
*/
#include
#include
using namespace std;
struct Value {};
template
struct greedy_struct {
static void run(const T&) {
cout << "const T& (struct)" << endl;
}
static void run(T&&) {
cout << "T&& (struct)" << endl;
}
};
// Per Toby's answer.
template
void greedy_sfinae(const T&) {
cout << "const T& (sfinae)" << endl;
}
template <
typename T,
typename = std::enable_if_t::value>>
void greedy_sfinae(T&&) {
cout << "T&& (sfinae)" << endl;
}
// Bad.
template
void greedy_sfinae_bad(const T&) {
cout << "const T& (sfinae bad)" << endl;
}
template <
typename T,
typename = std::enable_if_t::value>>
void greedy_sfinae_bad(T&&) {
cout << "T&& (sfinae bad)" << endl;
}
template
void greedy(TF&& value) {
using T = std::decay_t;
greedy_struct::run(std::forward(value));
greedy_sfinae(std::forward(value));
greedy_sfinae_bad(std::forward(value));
cout << "---" << endl;
}
int main() {
Value x;
const Value y;
greedy(x);
greedy(y);
greedy(Value{});
greedy(std::move(x));
return 0;
}