如何编写一个模板函数,使其能够接受 && 和 const& 两种类型的参数?

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

当我调用时
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

你想重载一个函数以区分r值和l值,而且类型也是模板化的吗? - Niall
你想让rvalue进入T&&重载,而lvalue进入T const &重载吗? - T.C.
可能相关:http://stackoverflow.com/q/25938749/3549027 - dlf
4
如果你不知道为什么这是一个问题,那是因为第一个重载函数采用了一种 _通用引用_(可以绑定到几乎任何东西),而不一定是看似的右值引用。这是因为在“推导”环境中,T&&的含义是不同的。欢迎来到C++。:/ - Lightness Races in Orbit
1
做你想做的事情几乎总是错误的。你是否了解完美转发?使用完美转发,你只需要T&&版本。 - fredoverflow
2个回答

7

这是一种方法:

#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) {}

另一种可能性是标签分派:
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>{} );
}

2
@P0W 我也是这么想的,但是不行 - jrok
啊,现在我看到了std::is_rvalue_reference的可能实现后才意识到。 - P0W
1
std::is_rvalue_reference< decltype(std::forward<T>(std::declval<T>())) 会起作用,不过 :) 或者使用 add_rvalue_reference<T>... - jrok
@Jarod42 谈论到因为树木而看不见森林的事情! - jrok

4
另一个选择是:
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


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接