3

For example

template<typename T> void f(T&& t) {}
template<typename T> void f(T const& t) {}

When I call

int i;
f(i); // call f(T&&) which I expect to call f(T const&), how to solve it?
f(10); // call f(T&&), that is fine
user1899020
  • 13,167
  • 21
  • 79
  • 154
  • Is that you wish to overload a function to discriminate between r-values and l-values and the type is also templated? – Niall Oct 03 '14 at 13:21
  • Do you want rvalues to go to the `T&&` overload and lvalues to go to the `T const &` overload? – T.C. Oct 03 '14 at 13:25
  • Possibly relevant: http://stackoverflow.com/q/25938749/3549027 – dlf Oct 03 '14 at 13:25
  • 4
    In case you didn't know why this is a problem, it's because that first overload takes a _universal reference_ (which can bind to just about anything), not necessarily an rvalue reference as it would first appear. It's because `T&&` means something different in a "deduced" context. Welcome to C++. :/ – Lightness Races in Orbit Oct 03 '14 at 13:29
  • 1
    Doing what you want to do is almost always wrong. Are you aware of Perfect Forwarding? With perfect forwarding, you only need the `T&&` version. – fredoverflow Oct 04 '14 at 07:49

2 Answers2

7

That'd be one way:

#include <type_traits>

template<typename T>
typename std::enable_if< !std::is_lvalue_reference<T>::value >::type
f(T&& t) {}

template<typename T> void f(T const& t) {}

Another possibility is tag dispatching:

template<typename T>
void f_(const T&, std::true_type) { std::cout << "const T&\n"; }
template<typename T>
void f_(T&&, std::false_type) { std::cout << "T&&\n"; }

template<typename T>
void f(T&& t)
{
    f_(std::forward<T>(t), std::is_lvalue_reference<T>{} );
}
jrok
  • 54,456
  • 9
  • 109
  • 141
  • 2
    @P0W That's what I thought, too, but [nope](http://coliru.stacked-crooked.com/a/c3c3048525a93b69). – jrok Oct 03 '14 at 13:34
  • Ahh now I realized after seeing the possible implementation of `std::is_rvalue_reference` – P0W Oct 03 '14 at 13:38
  • 1
    `std::is_rvalue_reference< decltype(std::forward(std::declval()))` would work, though :) Or with `add_rvalue_reference`... – jrok Oct 03 '14 at 13:43
  • @Jarod42 Talking about not seeing the forest because of the trees! – jrok Oct 03 '14 at 14:08
4

An other alternative is:

template<typename T>
struct f_caller
{
    void operator () (T&& ) { std::cout << "T&&" << std::endl; }
    void operator () (T const& ) { std::cout << "const T&" << std::endl; }
};


template <typename T>
void f(T&& t)
{
    f_caller<typename std::decay<T>::type>()(std::forward<T>(t));
}

Live example

Jarod42
  • 203,559
  • 14
  • 181
  • 302