对于具有默认模板参数的多态类,模板推导失败

Ath*_*ena 5 c++ polymorphism default-parameters template-argument-deduction

考虑这个例子:

#include <memory>

template<typename T>
class A {};

template<typename T1, typename T2>
class B: public A<T1> {};

template<typename T = int>
void foo(std::shared_ptr< A<T> > test)
{

}

int main()
{
    auto p = std::make_shared<B<int, int>>();
    foo<int>(p);    // Works
    foo<>(p);       // Does not work
    foo(p);         // Does not work
}
Run Code Online (Sandbox Code Playgroud)

我试图在没有为foo明确指定类型T的情况下编译它,但它不起作用.我不确定为什么好像我明确表示类型T,它工作正常,但如果我,它不编译,即使我已经告诉编译器,如果我不这样做类型T应该是什么明确指定它.

我明白为什么编译器不能推断类型T,但为什么我不指定它时它不能使用我的默认类型T?我如何解决这个问题以及"正确"的做法是什么?

lub*_*bgr 2

该问题与默认模板参数无关。p相反, ( )的类型std::shared_ptr<B<int, int>>无法与std::shared_ptr<T>模板的参数匹配foo相匹配:在模板参数推导过程中,不考虑任何转换,并且将派生类实例的引用作为基类引用传递确实是一种转换。

您可以通过显式向上转换管理的指针来解决该问题std::shared_ptr

std::shared_ptr<A<int>> p = std::make_shared<B<int, int>>();
Run Code Online (Sandbox Code Playgroud)

现在,这些调用将按预期进行:

foo<>(p); // Ok, argument matches the signature
foo(p);   // Same...
Run Code Online (Sandbox Code Playgroud)

请注意,模板参数类型是否出现在函数模板的参数列表中(使推导成为可能)有很大的不同。考虑这两个模板,

template <class T = int> void foo(T&&)
{
    std::cout << __PRETTY_FUNCTION__ << "\n";
}

template <class T = int> void bar(double)
{
    std::cout << __PRETTY_FUNCTION__ << "\n";
}
Run Code Online (Sandbox Code Playgroud)

两者都有默认类型int,但是当它们像这样实例化时

foo<>(0.0); // outputs: void foo(T&&) [with T = double]
bar<>(0.0); // outputs: void bar(double) [with T = int]
Run Code Online (Sandbox Code Playgroud)

第一个实例化使用函数参数来推导模板参数(结果为double),而第二个实例化则不推导任何内容,默认为int