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

Rak*_*111 14 c++ template-argument-deduction c++17

请考虑以下代码:

#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
}
Run Code Online (Sandbox Code Playgroud)

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
                 ^
Run Code Online (Sandbox Code Playgroud)

f是可转换的wrapper<int>,所以我希望会发生这种情况.从那里编译器应该能够推断出那Tint.但它不能.

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

有任何想法吗?

Sto*_*ica 11

对于类模板参数推导,"重载集"的组成如[over.match.class.deduct/1]中所述.这些是以下内容:

形成一组函数和函数模板,包括:
(1.1) - 对于由template-name指定的主类模板的每个构造函数,如果定义了模板,则具有以下属性的函数模板:
(1.1.1) -模板参数是类模板的模板参数,后跟构造函数的模板参数(包括默认模板参数)(如果有).
(1.1.2) - 函数参数的类型是构造函数的类型.
(1.1.3) - 返回类型是由模板名称和模板参数指定的类模板特化,对应于从类模板获得的模板参数.

(1.2) - 如果未定义主类模板C或未声明任何构造函数,则从假设构造函数C()中导出如上所述的附加函数模板.

(1.3) - 如上所述从假设构造函数C(C)派生的附加函数模板,称为复制推导候选者.

(1.4) - 对于每个演绎指南,具有以下属性的函数或函数模板:
(1.4.1) - 模板参数(如果有)和函数参数是演绎指南的参数.
(1.4.2) - 返回类型是演绎指南的simple-template-id.

如您所见,1.1中匹配的"函数"仅尝试将参数类型与模板参数类型完全匹配.它不需要考虑转换(很像大多数其他模板扣除相关的行为).

它适用的原因std::pair是由于项目1.3和它定义的"复制扣除候选人".