我想要如下设置:
template <typename T> class a {};
class b : public a<int> {};
template <typename T>
void do_foo(std::unique_ptr<a<T>> foo)
{
// Do something with foo
}
int main()
{
do_foo(std::make_unique<b>());
}
这无法编译,并显示 template argument deduction/substitution failed
和 mismatched types 'a<T>' and 'b'
.这是不言自明的。我可以通过写 do_foo<int>(std::make_unique<b>());
来帮助编译器。 ,但后来我通过写 int
重复我自己两次。在这种情况下,有没有办法让编译器推断出模板参数?你怎么称呼这种行为?我尝试搜索诸如“继承类型的模板类型推导”、“多态模板推导”等内容。
最佳答案
Is there a way to get the compiler to deduce the template parameter in this case?
不。不在 C++14(甚至 C++20)中。
And what would you call this behaviour?
符合标准。具体而言,本段适用于:
[temp.deduct.call]
4 In general, the deduction process attempts to find template argument values that will make the deduced
A
identical toA
(after the typeA
is transformed as described above). However, there are three cases that allow a difference:
- If the original
P
is a reference type, the deducedA
(i.e., the type referred to by the reference) can be more cv-qualified than the transformedA
.- The transformed
A
can be another pointer or pointer to member type that can be converted to the deducedA
via a qualification conversion ([conv.qual]).- If
P
is a class andP
has the form simple-template-id, then the transformedA
can be a derived class of the deducedA
. Likewise, ifP
is a pointer to a class of the form simple-template-id, the transformedA
can be a pointer to a derived class pointed to by the deducedA
.
这是一个详尽的案例列表,即使模板参数与函数参数的模式不完全匹配,也可以从函数参数中有效地推导出模板参数。第一个和第二个子弹处理诸如
template<class A1> void func(A1&){}
template<class A2> void func(A2*){}
int main() {
const int i = 1;
func(i); // A1 = const int
func(&i); // A2 = const int
}
第三个子弹是最接近我们案例的子弹。从模板特化派生的类可用于推导出与其基类相关的模板参数。为什么它在你的情况下不起作用?因为函数模板参数是unique_ptr<a<T>>
你调用它的参数是 unique_ptr<b>
. unique_ptr
特化本身与继承无关。所以它们与子弹不匹配,并且演绎失败。但这并不意味着像
unique_ptr
这样的包装器完全阻止模板参数推导。例如:template <typename> struct A {};
struct B : A<int> {};
template<typename> struct wrapper{};
template<> struct wrapper<B> : wrapper<A<int>> {};
template<typename T>
void do_smth(wrapper<A<T>>) {}
int main() {
do_smth(wrapper<B>{});
}
在这种情况下,wrapper<B>
源自 wrapper<A<int>>
.所以第三个要点是适用的。并且通过模板参数推导的复杂(和递归)过程,它允许 B
匹配 A<T>
并推导出 T = int
.TL;博士 :
unique_ptr<T>
特化不能复制原始指针的行为。它们不是从 unique_ptr
的特化继承而来的。在 T
的基地。也许如果反射出现在 C++ 中,我们将能够元编程一个具有这种行为的智能指针。
关于c++ - 从继承类型推导模板参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66356320/