Search code examples
c++templatesc++17c++20template-meta-programming

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


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.


Solution

  • 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&&) {}