C++ 具有通用引用的重载解析
我有一个函数,它可以通过通用引用接受任何类型,并希望为特定类型重载它(其中一些类型是模板化的,尽管我认为这在这里并不重要)。不幸的是,我似乎无法以正确的顺序解决重载问题 我认为C++ 具有通用引用的重载解析,c++,c++11,overloading,rvalue-reference,universal-reference,C++,C++11,Overloading,Rvalue Reference,Universal Reference,我有一个函数,它可以通过通用引用接受任何类型,并希望为特定类型重载它(其中一些类型是模板化的,尽管我认为这在这里并不重要)。不幸的是,我似乎无法以正确的顺序解决重载问题 我认为foo的第二个声明会更受欢迎,因为它更具体(模板更少),尽管看起来我对重载解析的理解有些欠缺。有趣的是,将第二个声明更改为按值获取X会使其打印“good,good”,而按非常量引用获取X会使其打印“bad,good”。显然,完全删除第一个声明会使它返回“good,good”,因为别无选择 那么为什么会发生这种情况呢?最重要
foo
的第二个声明会更受欢迎,因为它更具体(模板更少),尽管看起来我对重载解析的理解有些欠缺。有趣的是,将第二个声明更改为按值获取X
会使其打印“good,good”,而按非常量引用获取X
会使其打印“bad,good”。显然,完全删除第一个声明会使它返回“good,good”,因为别无选择
那么为什么会发生这种情况呢?最重要的是,如果下面的代码不起作用,如何用这个签名重载函数
#include <iostream>
#include <string>
class X {};
template<typename T>
inline std::string foo(T && rhs) {
return "bad";
}
inline std::string foo(const X & rhs) {
return "good";
}
int main() {
std::cout << foo(X()) << std::endl;
X x;
std::cout << foo(x) << std::endl;
return 0;
}
#包括
#包括
类X{};
模板
内联std::字符串foo(T&&rhs){
返回“坏”;
}
内联标准::字符串foo(常量X和rhs){
返回“好”;
}
int main(){
std::cout从X
到const X
的转换被认为比模板重载与T=X
或T=X&
的直接匹配更糟糕,以回答您的问题。对于Kerre的答案,您可以尝试使用SFINAE:
#include <type_traits>
#include <string>
template <class T>
struct HasFooImpl_ {
template <typename C>
static std::true_type test(decltype(fooImpl(std::declval<C>()))*);
template <typename C>
static std::false_type test(...);
typedef decltype(test<T>(0)) type;
};
template <typename T>
using HasFooImpl = typename HasFooImpl_<T>::type;
template <typename T>
typename std::enable_if<HasFooImpl<T>::value, std::string>::type
foo(T&& t)
{
return fooImpl(std::forward<T>(t));
}
template <typename T>
typename std::enable_if<!HasFooImpl<T>::value, std::string>::type
foo(T&& t)
{
return "generic!";
}
请参见如何使通用参考版本退居更具体版本的后面?@jleahy:您可以为X&
、X常量&
和X&
创建三个非模板重载,以覆盖所有情况……是:-)编辑:。@jleahy:或者,如果您只想排除X
,如果在模板中(和衰减)@jleahy我从问题中假设你的类型不仅仅是X,对吗?我正在为这些情况寻找答案。请继续关注;)@Arne Mertz是的,想法是X&&将是一个通用的回退。我喜欢这个。同样想法的另一个实现,但是使用表达式SFINAE而不是helper类,并且如果(缺点是它需要另一个间接层次)。实际上,我更喜欢后者的转换语义,而且实现非常简洁。非常好。我为重载部分想出了一个解决方案:在这个问题上花1个多小时,有趣的是,它又回到了这个问题。
#include <type_traits>
#include <string>
template <typename T> void fooImpl(T);
template <typename T>
using HasFooImpl = typename std::is_same<std::string, decltype(fooImpl(std::declval<T>()))>;
template <typename T>
typename std::enable_if<HasFooImpl<T>::value, std::string>::type
foo(T&& t)
{
return fooImpl(std::forward<T>(t));
}
template <typename T>
typename std::enable_if<!HasFooImpl<T>::value, std::string>::type
foo(T&& t)
{
return "generic!";
}