std::reference_wrapper没有operator<,所以唯一的方法ref_wrapper<ref_wrapper是通过ref_wrapper成员:
operator T& () const noexcept;
如您所知,std::string是:
typedef basic_string<char> string;
相关声明为string<string:
template<class charT, class traits, class Allocator>
bool operator< (const basic_string<charT,traits,Allocator>& lhs,
const basic_string<charT,traits,Allocator>& rhs) noexcept;
对于string<string这个函数声明模板是通过匹配string=实例化的,basic_string<charT,traits,Allocator>它解析为charT=char等。
因为std::reference_wrapper(或其任何(零)基类)不能匹配basic_string<charT,traits,Allocator>,所以函数声明模板不能实例化为函数声明,也不能参与重载。
这里重要的是没有非模板operator< (string, string)原型。
显示问题的最少代码
template <typename T>
class Parametrized {};
template <typename T>
void f (Parametrized<T>);
Parametrized<int> p_i;
class Convertible {
public:
operator Parametrized<int> ();
};
Convertible c;
int main() {
f (p_i); // deduce template parameter (T = int)
f (c); // error: cannot instantiate template
}
给出:
In function 'int main()':
Line 18: error: no matching function for call to 'f(Convertible&)'
标准引用
14.8.2.1 从函数调用中推导出模板参数 [temp.deduct.call]
模板参数推导是通过将每个函数模板参数类型(调用它P)与调用的相应参数类型(调用它)进行比较来完成的,A如下所述。
(...)
一般来说,推导过程试图找到模板参数值,使推导的值A与A(在A如上所述转换类型之后)相同。但是,有三种情况允许不同:
- 如果原始
P是引用类型,则推导的A(即引用所引用的类型)可以比转换后的 cv 更合格A。
请注意,这是std::string()<std::string().
- 转换的
A可以是另一个指针或指向成员类型的指针,可以A通过限定转换 (4.4) 转换为推导。
请参阅下面的评论。
- 如果
P是一个类并且P具有simple-template-id的形式,那么转换后的A可以是 deduced 的派生类A。
评论
这意味着在本段中:
14.8.1 显式模板参数规范 [temp.arg.explicit] /6
如果参数类型不包含参与模板参数推导的模板参数,则将对函数参数执行隐式转换(第 4 条)以将其转换为相应函数参数的类型。
if不应被视为if且仅当,因为它会直接与前面引用的文本相矛盾。