Must there be an unrelated specialization for compilation?

The following code (which compiles and runs properly, doing what I want) is the minimal example of the weirdness I experienced when writing a class to store properties of various types that needed the ability to remove pointers when they no longer knew their types. My solution was to create a Deleter class with a templated function that could have its own address, which would be selected and stored to delete a specific type. I do not understand why this code works , in particular:

  • Why didn’t he get into assert?
  • Why / how does it require / use (apparently) unrelated specialization?

code:

#include <iostream> #include <string> #include <cassert> #include <locale> //Just here as an unused class to specialize using namespace std; typedef void(*void_voidptr_func_t)(void*); class ClassWithDestructor { public: ~ClassWithDestructor() { cout << "Destroyed\n"; } }; class Deleter { public: template <class T> static void Delete (T* ptr) { assert(0); } //locale here can be any class //it doesn't matter what class it is //but if this specialization doesn't exist //compile fails template <class locale> static void Delete(void* ptr) { delete (locale*)ptr; } }; void* void_ptr_to_T = NULL; void_voidptr_func_t T_delete_function = NULL; template<class T> void A() { T* t = new T; void_ptr_to_T = (void*)t; T_delete_function = &Deleter::Delete<T>; } int main(int argc, char** argv) { A<ClassWithDestructor>(); T_delete_function(void_ptr_to_T); } 

Compiler: MSVC ++ 2010, disabled Microsoft extensions

Output:

destructible

+4
source share
2 answers

it

 template <class locale> static void Delete(void* ptr) { delete (locale*)ptr; } 

not a specialization. This is an overload. The specialization will be as follows:

 template <> static void Delete(locale* ptr) { delete (locale*)ptr; } 

So actually this is equivalent to writing only

 template <class T> static void Delete(void* ptr) { delete (T*)ptr; } 

Actually, the behavior that you presented is related to allowing line congestion

 T_delete_function = &Deleter::Delete<T>; 

The second overload is more specific since it accepts void* , not T* , and the type is explicitly specified anyway. Thus, in the presence of the aforementioned overload, he selects it, and it compiles and runs fine. In the absence of this more specific overload, the compiler calls another suitable, but more general, one that calls this statement.

You can double check this, i.e. remove the line #include <locale> : the compiler will not complain about the class locale not declared.

+5
source

There are no specializations: you have two (different) function templates that are overloaded:

 template <typename T> void Delete(T*); // (1) template <typename T> void Delete(void*); // (2) 

&Deleter::Delete<T> can refer to any of the Delete function templates. (2) is selected in your example because its type matches the type of function pointer you are assigning. Function pointer type void(*)(void*) ; type (1) , converted to a function pointer, is void(*)(T*) , which matches if T = void .

+3
source

All Articles