views:

115

answers:

3

A templated function gives me the convenience to operate on a variety of types:

template<typename T> void destroy(T* obj) {
    delete obj;
}

But at some point I want to do some specialization on a class hierarchy:

class Base { virtual void doSomething(); };
class Derived : public Base {};
void destroy(Base* obj) {
    obj->doSomething();
    delete obj;
}

The intended specialized function did invoked if I a pass the exact type Base*, however the rules of overload resolution seems to prefer the generic templated version instead of performing a static up cast if I a pass Derived* to void detroy().

Certainly I can make all the overloaded functions for all possible derived types, but it's less maintainable.

I am using Visual C++ 2008, is there any way around the above problem?

A: 

There's no such thing as Visual C++ 2009.

You may be able to specialize your function with another template and use SFINAE to only match subtypes of Base. But I don't know any reason the compiler would prefer the second version, usually a specialization has to be "better" in some way to be selected.

Alternatively, you could use SFINAE and a helper traits class to prevent the generic version from matching subclasses of Base. If you need an example of this, ask.

And of course your specialization will only be used where it's visible. Templated functions are always inline, they and specializations need to be in header files included by the caller.

Ben Voigt
+4  A: 

All things being equal, overload resolution prefers nontemplate functions to function templates. However, in this case, all things are not equal. To match your overload for Base*, a derived-to-base pointer conversion is necessary; no conversion is necessary to match the function template. Thus, the function template is selected for Derived*.

The "simple," albeit probably error-prone, solution would be to cast your Derived* to a Base* before you call the function.

You could, in theory at least, take an SFINAE approach as Ben suggests, but you would have to explicitly disable the generic function template for any types for which you provide specializations, otherwise you'll end up with overload ambiguities. This is even more unmaintainable and error-prone than the explicit cast approach. (Though, someone here may know of another way to get around the overload ambiguity; I'd certainly be interested to know if there was).

James McNellis
A: 

Just found a neat answer of the same problem in stack overflow:

Priority when choosing overloaded template functions in C++

Ricky Lung
@Ricky Lung: However your destroy function has a problem. It will be called for a 1D array type as well and you can land up doing 'delete' instead of 'delete []' which is undefined behavior.
Chubsdad