2017-06-18 84 views
13

考虑下面的代码:为什么编译器在与转换运算符一起使用时不能推导出模板参数?

#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>,所以我希望这样的事情发生。从那里编译器应该能够推断出Tint。但它不能。

编译器可以正确推导出std::pair的模板参数,所以我想知道为什么这不是wrapper

任何想法?

+0

IMO如果类模板扣除查看转换运算符,会引起混淆。如果需要的话,应该使用明确的扣除指南。 – cpplearner

+0

相关:https://stackoverflow.com/q/43019240/1896169 – Justin

+0

这是什么'运算符结构包装()'?它是否声明'operator wrapper'或'operator()'? – cat

回答

11

对于类模板参数推导,“过载集”的组成如[over.match.class.deduct/1]中所述。那些有以下几种:

形成一组的功能和功能模板,包括:
(1.1) - 对指定 由模板名称,如果模板被定义的主类模板的每个构造,函数模板 具有以下属性:
(1.1.1) - 模板参数是 类模板的模板参数随后模板 参数(包括默认模板参数)的构造的, 如果有的话。
(1.1.2) - 函数参数的类型是构造函数的 。
(1.1.3) - 返回类型是模板名称指定的类模板 ,模板参数 对应于从类 类获得的模板参数。 (1.2) - 如果未定义主类模板C或不声明任何构造函数,则从假设的构造函数C()中派生出如上所示的 的附加函数模板。

(1.3) - 从 假设构造函数C(C)导出的额外函数模板,称为复制推理候选。

(1.4) - 对每个扣导,具有 函数或函数模板以下属性:
(1.4.1) - 模板参数(如果有) 和功能参数是那些deduction-的指南。
(1.4.2) - 返回类型是扣减指南的简单模板标识。

正如你所看到的,在1.1匹配“功能”只尝试参数类型匹配的模板参数类型正是。它不考虑转换(与大多数其他模板演绎相关的行为非常相似)。

它适用于std::pair的原因归因于项目1.3和它定义的“复制扣除候选项”。

相关问题