具有通用引用的重载解析
Overload resolution with universal references
我有一个函数,它可以通过通用引用接受任何类型,并希望为特定类型重载它(其中一些类型本身是模板化的,尽管我认为这在这里并不重要)。不幸的是,我似乎不能以正确的顺序解决重载。
我本以为foo
的第二个声明会更受欢迎,因为它更具体(更少模板化),尽管看起来我对重载解析的理解有所欠缺。有趣的是,将第二个声明改为按值取X
使其打印"good, good",而将X
改为非const引用则使其打印"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;
}
编辑:也许一个更迂回的解决方案是间接地做到这一点。去掉foo
的第一种形式,使用SFINAE检查是否存在有效的过载,如果没有,则调用foo_fallback
。
要回答您的问题。评论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!";
}
你必须实现一个函数fooImpl
对于任何类型,你不希望被一般处理。
实现有点棘手,我首先尝试了enable_if<is_same<string, decltype(fooImpl(declval<C>()))>::value
,但是对于后退!is_same<>::value
给了我编译器错误,因为它也试图实例化decltype。
这个实现有一个注意事项,您可能想使用,也可能不想使用:如果T
可转换为定义了fooImpl
的其他类型,则转换将开始。
您可以在这里看到整个操作:http://ideone.com/3Tjtvj
更新:如果您不想允许类型转换,它实际上变得更简单:
#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!";
}
见http://ideone.com/miaoop
从X
到const X
的转换被认为比直接匹配T = X
或T = X &
的模板化重载更糟糕。
- 取消引用运算符不能重载
- 错误:无法解析对重载函数的引用;你的意思是调用它吗?
- 传递空初始值设定项列表时使用右值和左值引用候选项的重载解析
- 为什么我的运算符 + 重载尽管是通过引用传递的,但仍调用我的复制构造函数?
- C++编程:运算符重载中的引用如何工作?
- 重载运算符*以获取对另一个类的实例的引用
- 对运算符=使用通用引用,而不是多个重载
- 如何重载下标运算符 [] 以引用 2d STL 数组?
- 具有参数包和通用引用的重载选择
- 当有右值构造函数可用时,为什么从右值调用类引用构造函数重载?
- C++:对函子重载调用运算符的未定义引用
- 运算符重载C++类中的引用返回
- 错误:无法解析对重载函数的引用
- 两个相同的重载运算符[]一个返回引用
- 在函数重载中将右值引用实现为参数
- 模板流运算符重载错误:引用初始化无效,与basic_istream和basic_ifstream之间的差异有关
- 运算符重载C++引用或值
- C++类模板构造函数 -- 重载引用 (U&) 与数组 (U*) 失败
- C++ 类运算符重载引用
- 重载引用与const引用