Home > Net >  Is enable_if the most concise way to define a function accepting only rvalues, but of any type?
Is enable_if the most concise way to define a function accepting only rvalues, but of any type?

Time:07-05

I'm referring to this:

#include <utility>

template<typename T, typename = std::enable_if_t<std::is_rvalue_reference_v<T&&>>>
auto f(T&&) {}

int main(){
    int i{};
    f(std::move(i)); // ok
    f(int{1});       // ok
    f(i);            // compile time error, as expected
}

Are there any other, shorter ways to accomplish the same?

For a moment I thought something like this could work

template<typename T>
auto f(decltype(std::declval<T>())&&) {}

but the IDE told me couldn't infer template argument 'T', and I verified here, in the section Non-deduced contexts, that the expression of a decltype-specifier is indeed a non-deduced context.


I'm interested also in a solution, if any exists.

CodePudding user response:

Did you try explicitly deleting the l-value overload?

template <typename T>
auto f(T &&) {}

template <typename T>
auto f(T &) = delete;

CodePudding user response:

You can use static_assert if you don't need SFINAE:

template<typename T>
auto f(T&&) {
    static_assert(std::is_rvalue_reference_v<T&&>);
}

CodePudding user response:

As @HolyBlackCat commented, you can use concepts to simplify the function signature

#include <type_traits>

template<typename T>
  requires (!std::is_lvalue_reference_v<T>)
auto f(T&&) {}

Or detect lvalue or rvalue by checking the validity of a lambda expression that accepts an lvalue reference

#include <utility>

template<typename T>
  requires (!requires (T&& x) { [](auto&){}(std::forward<T>(x)); })
auto f(T&&) {}
  • Related