Failed to determine function template specialization?

#include <iostream> template <class T> void foo(T) { std::cout << "foo(T)" << std::endl; } template <class T> void foo(T*) { //#3 std::cout << "foo(T*)" << std::endl; } #define TEST #ifdef TEST template <> void foo(int*) { //#1 std::cout << "foo(int*)" << std::endl; } #else template <> void foo<int*>(int*) { //#2 std::cout << "foo<int*>(int*)" << std::endl; } #endif int main(int argc, char **argv) { int* p = 0; foo(p); return 0; } 

what's the difference between # 1 and # 2. If I define TEST, # 1 works. But if I comment on this, No. 3 work ... And what is the right way to write a specialization of function templates ...

+6
source share
3 answers

# 1 declares the specialization of function template No. 3 and automatically displays the template parameters. # 2 is a specialization of the first template you selected (number without number, let it be called # 0) for T=int* . It cannot be specialization # 3, because instead of T with the specified int* this will result in the parameter int** .

When you call foo , overload resolution now selects the most appropriate base pattern, and then checks this pattern for any existing specializations. If TEST is defined, there are two basic patterns (# 0 and # 3), and # 3 is the best match and choice. Then the compiler checks the specializations of this template, and # 1 is better suited and called.

Without TEST , there are two more basic patterns (# 0 and # 3), and # 3 is the best match and is chosen. Then the compiler checks the specializations of this template, but since # 2 specializes in # 0 and not # 3, it is not considered and the 3rd end ends.

This is a classic example. Why not specialize function templates . The problems are explained in more detail here.

A simple solution is to not specialize function templates in general, but simply add new overloads for special types:

 // no template, just a normal function void foo(int*) { std::cout << "foo(int*)" << std::endl; } 
+3
source

For specialized template templates, you can explicitly specify template arguments, but you do not need to if the template arguments are output. If you do not specify template arguments, they will be output by the compiler using the same rules as overload resolution. To determine which overload function should be selected, the compiler begins by examining only the primary patterns (which are primarily selected by some kind of magical process). View two available primary templates

 template <typename T> void foo(T); template <typename T> void foo(T*); 

the latter is the best match for a pointer argument. Once the correct primary template is found, the compiler searches for potential specializations of this primary template. However, your example # 2 is not actually a specialization of a function template that takes a pointer argument, although it does include a pointer argument. If you take the main ad

 template <typename T> void foo(T*); 

and you replace T with an explicitly specified argument to the int* template, you get

 template <> void foo<int*>(int**); 

I.e. ad

 template <> void foo<int*>(int*); 

is something else. You probably just want to lose the pointer when specifying the template argument:

 template <> void foo<int>(int*); 
+2
source

I canโ€™t say which function # 2 should specialize, or exactly how extremely complex overload resolution rules will select a function to call.

I know that more often than not you need to specialize functions, but you can rely on overload instead. To get a function for int* , you just need

 void foo(int*) { std::cout << "foo(int*)" << std::endl; } 

A function without a template will be preferable over templates if the parameter matches.

0
source

Source: https://habr.com/ru/post/906532/


All Articles