Search code examples
c++c++11templatesrvalue-referenceforwarding-reference

How to get different overloads for rvalue and lvalue references with a template-deduced type?


I have a function foo taking a parameter by reference, and I want it to act differently on rvalue and on lvalue references. (I should also mention foo() respects constness; it doesn't change the refered-to value.) I know that if I write:

template <typename T> foo(T&& x);

I've declared a forwarding reference, rather than an rvalue reference, meaning that this way:

template <typename T> foo(const T& x);
template <typename T> foo(T&& x);

likely won't get me what I want.

So, my question is: What's the right way to affect different behavior between the two kinds of references?


Solution

  • Tag dispatching is the simplest solution.

    namespace details {
      template <typename T>
      void foo(std::true_type is_lvalue, const T& x) {
        std::cout << x << " is an lvalue\n";
      }
      template <typename T>
      void foo(std::false_type is_lvalue, T&& x) {
        std::cout << x << " is an rvalue\n";
      }
    }
    template <typename T>
    void foo(T&& t) {
      return details::foo(
        typename std::is_lvalue_reference<T>::type{},
        std::forward<T>(t)
      );
    }
    

    SFINAE is serious overkill when you don't actually want to support neither version being selected for overload resolution purposes.