0

У меня есть шаблон функции, который я специализировал для определенного типа. У меня возникли проблемы с получением специализированной версии в определенных обстоятельствах. Для иллюстрацииСпециализация шаблона функции, не вызываемая для производного типа

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"; 
} 

Теперь, если я построить экземпляр «базы» или «производный» и называем «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 

}

Но предположим, что у меня есть промежуточный шаблон функции между этими двумя, что вызывает Foo Внутренний. В этом случае разрешение шаблон для производного типа, кажется, не в состоянии по пути

// 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, как это было, когда вызов был прямым. Разве компилятор не понимает, что это происходит от «Базы» в этом случае? Какое правило я пропущу здесь?

Я использую обновление Microsoft Visual Studio 2012 Update 3, если это имеет значение.

-Joe

+0

С тегом [C++] вы получите больше внимания и ** подсветку синтаксиса **. – dyp

+0

У вас есть явная (полная) специализация для 'Base &', тогда как тип, который вы используете в явной спецификации, используемой для вызова 'FooInternal', это' Derived', а не 'Base'. – dyp

+0

Я понимаю, что я использую Derived в этом вызове. Но это не объясняет, почему это работает, когда я вызываю FooInternal напрямую с Derived. Не следует ли вызвать тот факт, что Foo приводит к тому, что компилятор делает такое же разрешение, когда я вызывал Foo напрямую? – user2057722

ответ

1

Ваше ожидание в первом примере, и, по-видимому, также компилятор, неверны. Результат должен быть «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); 
} 

Это должно получить, что вы искали (на всех компиляторов).

+0

Если бы я должен был взять эту функцию и превратить ее в класс (например, объект функции), должен ли компилятор - в соответствии с правилами C++ - выводить аргументы и вызывать функции, как я пытался здесь? Или я столкнулся с той же проблемой? Мне нужен std :: enable_if и std :: is_base_of? – user2057722

+0

@ user2057722 IIRC Единственная точка, где тип выводится для шаблонов классов, - это * частичная специализация *. Выделения для явных (полных) специализаций нет. Вы можете использовать SFINAE через 'enable_if' и' is_base_of' для выбора * частичной специализации * (для шаблона класса), это может «решить» вашу проблему (хотя я согласен с aschepler, что проще перегрузить шаблон функции). – dyp

+0

Непонятно, что вы имеете в виду под этим вопросом. – aschepler