函数模板特化未调用派生类型

时间:2013-07-18 21:17:18

标签: c++ templates template-specialization overload-resolution function-templates

我有一个专门针对特定类型的功能模板。在某些情况下我无法调用专用版本。为了说明

struct Base {};
struct Derived : public Base {};


template <typename VALTYPE> void FooInternal(VALTYPE&) 
{
    std::cout << L"FooInternal template";
}

template<> void FooInternal(Base&) 
{
    std::cout << L"FooInternal SPECIAL"; 
}

现在,如果我构建一个“Base”或“Derived”的实例并调用“FooInternal”,那么所有的工作都如我所料

int _tmain(int argc, _TCHAR* argv[])
{
    int x = 7;
    FooInternal(x);  // Calls FooInternal<VALTYPE>() template

    Base b;
    FooIntenral(b);  // Calls FooInternal<Base>() specialization

    Derived d;
    FooInternal(d);  // Calls FooInternal<Base>() specialization

    return 0;
}

这是

的输出
FooInternal template
FooInternal SPECIAL
FooInternal SPECIAL

}

但是假设我在这两者之间有一个调用FooInternal的中间函数模板。在这种情况下,派生类型的模板分辨率似乎在路上失败

// Intermediate template.  Just calls FooInternal.

template<typename VALTYPE>
void Foo(VALTYPE& val)
{
    FooInternal<VALTYPE>(val);
}


// Now repeat the same 3 calls and see what happens with Derived...

int _tmain(int argc, _TCHAR* argv[])
{
    int x = 7;
    Foo(x);  // Calls FooInternal<VALTYPE>() template

    Base b;
    Foo(b);  // Calls FooInternal<Base>() specialization

    Derived d;
    Foo(d);  // Calls FooInternal<VALTYPE>() template!!!

    return 0;
}

该程序的输出是

FooInternal template
FooInternal SPECIAL
FooInternal template

我无法理解为什么 - 在第3次调用中,“Foo”将不会调用FooInternal的专用版本,就像调用是直接调用时一样。编译器是否应该理解在这种情况下从'Base'派生出来?我在这里错过了什么规则?

我正在使用Microsoft Visual Studio 2012 Update 3,如果这很重要。

-Joe

1 个答案:

答案 0 :(得分:1)

您在第一个示例中的期望,显然也是您的编译器,是错误的。输出应为“FooInternal templateFooInternal SPECIALFooInternal模板”。

函数模板特化对模板参数推导或重载解析没有任何作用。只有在没有查看规则的情况下,才能使用完全相同的模板参数。

大多数情况下,当您认为自己需要函数模板专业化时,最好重新设置函数(使用其他模板或使用非模板)。

inline void FooInternal(Base&) 
{
    std::cout << L"FooInternal SPECIAL"; 
}

当然,如果您指定模板参数,则永远不会调用FooInternal,因此您需要:

// Intermediate template.  Just calls FooInternal.

template<typename VALTYPE>
void Foo(VALTYPE& val)
{
    FooInternal(val);
}

这可以让你得到你想要的东西(在所有编译器上)。