当与转换运算符一起使用时,为什么编译器不能推导出模板参数?

时间:2017-06-18 06:01:16

标签: c++ c++17 template-deduction

请考虑以下代码:

#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的情况并非如此。

有什么想法吗?

1 个答案:

答案 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和它定义的“复制扣除候选人”。