具有部分特化的类模板参数推导

3

我有些困难理解新的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);
              ^

为什么会发生这种情况?
1个回答

8

类模板参数推导仅考虑主类模板中的构造函数以进行推导。在第一个示例中,我们有一个构造函数,为其合成了一个函数模板:

template <class T> A<T> __f(T );
__f(b)的结果是A<B>,我们完成了。
但在第二个例子中,主类模板只是:
template <typename T, typename = T>
struct A;

它没有构造函数,因此我们没有可以从中合成的函数模板。我们只有一个假设的默认构造函数复制推导指南,它们一起给我们提供了这个重载集:

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)可以正常工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接