请考虑以下代码:
#include <utility>
template<typename T>
struct wrapper {
T value;
};
struct foo {
operator wrapper<int>() {
return{10};
}
};
int main() {
foo f;
wrapper w = f; // error
std::pair p = std::make_pair(1, 0); // ok
}
gcc 7.1.1无法在上面的标记行进行编译:
main.cpp: In function 'int main()': main.cpp:17:17: error: class template argument deduction failed: wrapper w = f; // error ^ main.cpp:17:17: error: no matching function for call to 'wrapper(foo&)' main.cpp:4:8: note: candidate: template<class T> wrapper(wrapper<T>)-> wrapper<T> struct wrapper { ^~~~~~~ main.cpp:4:8: note: template argument deduction/substitution failed: main.cpp:17:17: note: 'foo' is not derived from 'wrapper<T>' wrapper w = f; // error ^
f
可以转换为wrapper<int>
,所以我希望这会发生。从那里编译器应该能够推断T
是int
。但它不能。
编译器可以正确推导出std::pair
的模板参数,因此我想知道为什么wrapper
的情况并非如此。
有什么想法吗?
答案 0 :(得分:11)
对于类模板参数推导,“重载集”的组成如[over.match.class.deduct/1]中所述。这些是:
形成一组功能和功能模板,包括:
(1.1) - 为指定的主类模板的每个构造函数 通过template-name,如果定义了模板,则为函数模板 具有以下属性:
(1.1.1) - 模板参数是 类模板的模板参数后跟模板 构造函数的参数(包括默认模板参数), 如果有的话。
(1.1.2) - 函数参数的类型是 构造函数。
(1.1.3) - 返回类型是类模板 由template-name和template参数指定的特化 对应于从类中获得的模板参数 模板。(1.2) - 如果未定义主类模板C或未定义 声明任何构造函数,派生为的附加函数模板 以上来自假设的构造函数C()。
(1.3) - 从a中导出的附加函数模板 假设的构造函数C(C),称为复制推导候选者。
(1.4) - 对于每个演绎指南,一个函数或函数模板 以下属性:
(1.4.1) - 模板参数,如果有的话, 和功能参数是演绎指南的参数 (1.4.2) - 返回类型是演绎指南的simple-template-id。
如您所见,1.1中匹配的“函数”仅尝试将参数类型与模板参数类型完全匹配。它不需要考虑转换(很像大多数其他模板扣除相关的行为)。
它适用于std::pair
的原因是由于项目1.3和它定义的“复制扣除候选人”。