我在理解新C ++ 17功能的所有限制方面遇到了一些麻烦,该功能允许在构造函数上进行模板推理。
特别是,此示例正确编译:
struct B {};
template <typename T, typename = T>
struct A {
A(T) {}
};
int main() {
B b;
A a(b); // ok
}
虽然这个没有:
struct B {};
template <typename T, typename = T>
struct A;
template <typename T>
struct A<T> {
A(T) {}
};
int main() {
B b;
A a(b); // error
}
第二种情况的错误是:
main.cpp: In function ‘int main()’:
main.cpp:17:14: error: class template argument deduction failed:
A a(b);
^
main.cpp:17:14: error: no matching function for call to ‘A(B&)’
main.cpp:4:12: note: candidate: template<class T, class> A(A<T, <template-parameter-1-2> >)-> A<T, <template-parameter-1-2> >
struct A;
^
main.cpp:4:12: note: template argument deduction/substitution failed:
main.cpp:17:14: note: ‘B’ is not derived from ‘A<T, <template-parameter-1-2> >’
A a(b);
^
为什么会这样?
答案 0 :(得分:6)
类模板参数推导仅考虑主类模板中的构造函数以进行推导。在第一个例子中,我们有一个构造函数,我们为:
合成一个函数模板template <class T> A<T> __f(T );
__f(b)
的结果是A<B>
,我们已经完成了。
但是在第二个例子中,主类模板只是:
template <typename T, typename = T>
struct A;
它没有构造函数,因此我们没有函数模板可以从中进行合成。我们所拥有的只是hypothetical default constructor和copy deduction guide,它们共同为我们提供了这个重载集:
template <class T> A<T> __f();
template <class T> A<T> __f(A<T> );
__f(b)
都不可行(你得到的编译错误是关于尝试匹配复制扣除指南),因此扣除失败。
如果你希望这个成功,你必须写一个演绎指南:
template <class T>
A(T ) -> A<T>;
允许A a(b)
工作。