开发者

Unrelated specialization must exist to compile?

The following code (which compiles and executes properly, doing what I want) is a minimal example of an oddity I experienced while writing a class to store properties of various types that needed the ability to delete pointers when it no longer knows their types. My solution was to make a Deleter class with a templated function that could have its address taken and stored to delete a specific type. I don't understand why this code works, specifically:开发者_开发百科

  • Why doesn't it hit the assert?
  • Why/how does it require/use the (seemingly) 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, Microsoft Extensions Disabled

Output:

Destroyed


This

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

is not a specialization. This is an overload. A specialization would be like this

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

So actually it's equivalent to writing just

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

Actually, the behavior you presented is because of the overload resolution on the line

T_delete_function = &Deleter::Delete<T>;

The second overload is more specific as it accepts void* and not T* and type is specified explicitly anyway. So in presence of the mentioned overload it chooses it and it compiles and runs finely. In absence of this more specific overload, compiler calls another appropriate, but more general one which fires the assertion.

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


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

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

&Deleter::Delete<T> could refer to either of the Delete function templates. (2) is selected in your example because its type matches the type of the function pointer to which you are assigning. The type of the function pointer is void(*)(void*); the type of (1) converted to a function pointer is void(*)(T*), which does match unless T = void.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜