0

I've looked around and not found quite what I'm looking for. Basically I want a function template specialized by a base class. I don't know how to make it use the specialized function.

Meaning...

class IBase
{
public:
    virtual std::string func() const = 0;
};

class MyClass : public IBase
{
public:
    std::string func() const { return "From MyClass"; }
};

template <class T>
std::string get_func(const T* t)
{
    return "Unknown";
}

template <>
std::string get_func<IBase>(const IBase* t)
{
    return t->func();
}

int main()
{
    int a;
    MyClass b;

    get_func(&a); // <- Returns 'Unknown'. Good.
    get_func(&b); // <- Returns 'Unknown'. Bad, want 'From MyClass'.
}

The reason I use const T* is because IBase is abstract.

dyp
  • 38,334
  • 13
  • 112
  • 177
kmdreko
  • 42,554
  • 6
  • 57
  • 106
  • Please always add a language tag to your question. This also enables (automatic) syntax highlighting. – dyp Feb 04 '14 at 22:20
  • 1
    Typically, you don't want to specialize a function template, but overload it. In your case, this would also solve the problem: The specialization is *only* used if the type deduced for the argument of the function call matches exactly the type you specialized it with. – dyp Feb 04 '14 at 22:23
  • True. On the other hand, function templates are strictly stronger than function overloads. There are things you can do with function templates but not with overloads. – thor Feb 04 '14 at 22:40

2 Answers2

1

Just use an overloaded function instead.

std::string get_func(const IBase *t) {
    return t->func();
}

Overloaded functions are always selected before templates.

villintehaspam
  • 8,540
  • 6
  • 45
  • 76
0

Using function overloads in the accepted answer to replace function template specialization isn't always a good idea. For the example code in the question, function overloading cannot provide a default implementation which prints "Unknown" for non-specialized classes. Other examples where function overloading is insufficient include tuples and virtually any variadic programming.

The primary reason why the code in question doesn't work is that currently, type deduction and conversion do not play nicely with each other. You need to cast &b to a pointer type to its parent class (i.e. IBase*) which the specialized function expects. Because of this issue in current C++, it's necessary to help out the compiler by using.

get_func((const IBase*)&b);

secondly, it may be better to add virtual to

std::string func() const { return "From MyClass"; } 

,since IBase::func is defined as a virtual member function. (This isn't necessary for all compilers: C++ "virtual" keyword for functions in derived classes. Is it necessary?).

With these changes, code below outputs what's expected:

Unknown
From MyClass

Code:

#include <string>
#include <iostream>
using namespace std;

class IBase
{
public:
    virtual std::string func() const = 0;
};

class MyClass : public IBase
{
public:
    virtual std::string func() const { return "From MyClass"; }
};

template <class T>
std::string get_func(const T* t)
{
    return "Unknown";
}

template <>
std::string get_func<IBase>(const IBase* t)
{
    return t->func();
}

int main()
{
    int a;
    MyClass b;

    cout << get_func(&a) << endl; // <- Returns 'Unknown'. Good.
    cout << get_func((const IBase*)&b) << endl; // 
}
Community
  • 1
  • 1
thor
  • 21,418
  • 31
  • 87
  • 173
  • If you really really need to make the function template specialized, it may be better to use the technique discussed in the article below by Herb Sutter, where you instead let the function delegate the functionality to a templated class that is easier to specialize. Usually, just using an overloaded gets the job done quicker and cleaner though. See http://www.gotw.ca/publications/mill17.htm – villintehaspam Jun 26 '14 at 07:23
  • agreed. that technique is even more powerful than func templates. I'm using func templates because it's shorter and closer to OP – thor Jun 26 '14 at 15:11