从继承类型推导模板参数

jez*_*zza 5 c++ polymorphism templates c++14

我想要如下设置:

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

这无法通过注释说template argument deduction/substitution failed和进行编译mismatched types 'a<T>' and 'b'。这是不言自明的。我可以通过编写 来帮助编译器do_foo<int>(std::make_unique<b>());,但是我通过编写int两次来重复自己。

在这种情况下,有没有办法让编译器推断出模板参数?你怎么称呼这种行为?我尝试搜索诸如“继承类型的模板类型推导”、“多态模板推导”等内容。

Sto*_*ica 2

在这种情况下有没有办法让编译器推断出模板参数?

不,C++14(甚至 C++20)中没有。

您将这种行为称为什么?

符合标准。具体来说,本段适用:

[临时扣费电话]

4一般来说,推导过程会尝试找到模板参数值,使推导结果与(如上所述进行类型转换后)A相同。但是,在三种情况下允许存在差异:A A

  • 如果原始类型P是引用类型,则推导的A(即引用所引用的类型)可以比转换后的 更符合 cv 条件A
  • 转换后的对象A可以是另一个指针或指向成员类型的指针,可以A通过限定转换 ([conv.qual]) 转换为推导的类型。
  • 如果P是一个类并且具有simple-template-idP形式,则转换后的可以是推导的派生类。同样,如果是指向simple-template-id形式的类的指针 ,则转换后的可以是指向由推导的 所指向的派生类的指针。AAPAA

这是一个详尽的案例列表,其中模板参数可以从函数参数中有效推导,即使它与函数参数的模式不完全匹配。第一个和第二个项目符号处理诸如

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

第三个项目符号是最接近我们的情况的。从模板特化派生的类可用于推导与其基类相关的模板参数。为什么它在你的情况下不起作用?因为函数模板参数是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>{});
}
Run Code Online (Sandbox Code Playgroud)

在本例中,wrapper<B>派生自wrapper<A<int>>. 所以第三条是适用的。并且通过模板参数推导的复杂(和递归)过程,它允许B匹配A<T>和推导T = int

TL;DRunique_ptr<T>专业化无法复制原始指针的行为。它们不继承unique_ptroverT的基础的专业化。也许如果反射出现在 C++ 中,我们将能够对一个具有这种行为方式的智能指针进行元编程。