У меня есть шаблон функции, который я специализировал для определенного типа. У меня проблемы с получением специализированной версии для вызова при определенных обстоятельствах. Проиллюстрировать
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, если это имеет значение.
-Джо
Ваши ожидания в первом примере, а также, по-видимому, и ваш компилятор, неверны. Вывод должен быть «FooInternal templateFooInternal SPECIALFooInternal template».
Специализация шаблона функции ничего не делает для вывода аргумента шаблона или разрешения перегрузки. Он используется только в том случае, если правила, не смотря на это, оказываются в точности такими же аргументами шаблона.
Большую часть времени, когда вы думаете, что хотите специализацию шаблона функции, было бы лучше вместо этого перегрузить функцию (с другим шаблоном или без шаблона).
inline void FooInternal(Base&)
{
std::cout << L"FooInternal SPECIAL";
}
И тогда, конечно, что FooInternal
никогда не может быть вызван, если вы указали аргументы шаблона, поэтому вы хотите:
// Intermediate template. Just calls FooInternal.
template<typename VALTYPE>
void Foo(VALTYPE& val)
{
FooInternal(val);
}
Это должно получить то, что вы искали (на всех компиляторах).
Других решений пока нет …