Простой способ - предоставить удаленный элемент , который принимает ссылку lvalue:
template<typename T> void receive_ownership(T&) = delete;
Это всегда будет лучшим соответствием для аргумента lvalue.
Если у вас есть функция, которая принимает несколько аргументов, все из которых должны быть значениями r, нам понадобится несколько удаленных функций. В этой ситуации мы можем предпочесть использовать SFINAE, чтобы скрыть функцию от любых аргументов lvalue.
Одним из способов сделать это может быть C ++ 17 и Concepts TS:
#include <type_traits>
template<typename T>
void receive_ownership(T&& t)
requires !std::is_lvalue_reference<T>::value
{
// taking file descriptor of t, and clear t
}
или
#include <type_traits>
void receive_ownership(auto&& t)
requires std::is_rvalue_reference<decltype(t)>::value
{
// taking file descriptor of t, and clear t
}
Пройдя немного дальше, вы сможете определить собственную новую концепцию, которая может быть полезна, если вы хотите использовать ее повторно, или просто для большей ясности:
#include <type_traits>
template<typename T>
concept bool rvalue = std::is_rvalue_reference<T&&>::value;
void receive_ownership(rvalue&& t)
{
// taking file descriptor of t, and clear t
}
Примечание: в GCC 6.1 вам необходимо передать -fconcepts
компилятору, так как это расширение C ++ 17, а не его основная часть.
Просто для полноты вот мой простой тест:
#include <utility>
int main()
{
int a = 0;
receive_ownership(a); // error
receive_ownership(std::move(a)); // okay
const int b = 0;
receive_ownership(b); // error
receive_ownership(std::move(b)); // allowed - but unwise
}