elemakil
elemakil

Reputation: 3811

Overload recursively based on template parameter

When playing around with good ol' c++ I started wondering whether it is possible to overload a template function based on an enclosing template. At the first layer this looks achievable, however, how can this be done recursively? So that the below pseudo-c++ code

#include <iostream>
#include <vector>
#include <map>

template <typename T> void magic(){
    std::cout << "Called magic<T>" << std::endl;
}

template <typename std::vector<T> > void magic(){
    std::cout << "Called magic<std::vector<T> >" << std::endl;
    magic<T>();
}

template <typename std::map<T,U> > void magic(){
    std::cout << "Called magic<std::map<T,U> >" << std::endl;
    magic<T>();
    magic<U>();
}


int main() {
    magic<std::vector<std::map<std::string,std::vector<int> > > >();
}

yields something like:

Called magic<std::vector<T> >
Called magic<std::map<T,U> >
Called magic<T>
Called magic<std::vector<T> >
Called magic<T>

In principle this does not look like it should be impossible because all the type info is available at compile time. The compiler could easily create all required functions since the recursion is bound to stop. And thus the question: Is this possible? If so, how?

Upvotes: 0

Views: 48

Answers (2)

leemes
leemes

Reputation: 45685

You need partial template specialization, that is a template specialization which itself is a template again.

That is not possible with function templates but it is with classes. So the workaround is to create a class template (here called Magic) with the specializations. Within that class, a simple (non-template) function is called.

Then, a function magic forwards to that class in order to hide that "hack":

Live demo of this code snippet

#include <iostream>
#include <vector>
#include <map>

// Forward declaration of the magic function:
template <typename> void magic();

// General case:
template <typename T>
struct Magic {
    static void m(){
        std::cout << "Called magic<T>" << std::endl;
    }
};

// Vector case:
template <typename T>
struct Magic<std::vector<T> > {
    static void m(){
        std::cout << "Called magic<std::vector<T> >" << std::endl;
        magic<T>();
    }
};

// Map case:
template <typename T, typename U>
struct Magic<std::map<T,U> > {
    static void m(){
        std::cout << "Called magic<std::map<T> >" << std::endl;
        magic<T>();
        magic<U>();
    }
};

// Implementation of the magic function:
template <typename T>
void magic() {
    std::cout << "Forwarding..." << std::endl;
    Magic<T>::m();
}

int main() {
    magic<std::vector<std::map<std::string,std::vector<int> > > >();
}

Upvotes: 1

Kerrek SB
Kerrek SB

Reputation: 477150

Simple specialization should do the trick, but bear in mind that you cannot specialize function templates partially, so you'll need an intermediate class template:

template <typename> void magic();

template <typename T>
struct Impl 
{
    static void f() { std::cout << "Primary template\n"; }
};

template <typename T, typename A>
struct Impl<std::vector<T, A>>
{
    static void f() { std::cout << "A vector\n"; magic<T>(); }
};

template <typename K, typename T, typename P, typename A>
struct Impl<std::map<K, T, P, A>>
{
    static void f() { std::cout << "A map\n"; magic<K>(); magic<T>(); }
};

template <typename T> void magic() { Impl<T>::f(); }

Upvotes: 3

Related Questions