Madden
Madden

Reputation: 1080

Templates: Get type and map to function

I currently have a series of C++ functions that each call to a C function located elsewhere, these functions essentially do the same thing but return different types. I would like to be able to dynamically get the type of a template and call the associated function, something like

template<typename T>
T getVal(const char* id) {
    return funcMap[T.someIdentifyingMethod](id);
}

Is this possible and if so how would I go about it?

Upvotes: 0

Views: 279

Answers (4)

Guillaume Racicot
Guillaume Racicot

Reputation: 41780

I usually use this trick. It associate a type with an object:

using type_id_t = void(*)();
template<typename T> void type_id(){}

Now, we can match an object (in your case, a function) with the function pointer of this template:

std::map<type_id_t, void(*)(const char*)> funcs;

And fill the map:

funcs[type_id<int>] = myFunc1;
funcs[type_id<double>] = myFunc2;
funcs[type_id<SomeOtherType>] = myFunc3;

Now you can retrieve them like this:

template<typename T>
T getVal(const char* id) {
    return reinterpret_cast<T(*)(const char*)>(funcMap[type_id<T>])(id);
}

Upvotes: 0

eerorika
eerorika

Reputation: 238351

Template specialization indeed sems like what you're looking for. Here's how to specialize your free function, instead of a static member function that Simple proposed:

template<typename T>
T getVal(const char* id); // leave undefined to fail compilation when no specialization exists

template<>
int getVal(const char* id) {
    return c_function_that_returns_int(id);
}

template<>
foo getVal(const char* id) {
    return c_function_that_returns_foo(id);
}

Upvotes: 1

YSC
YSC

Reputation: 40080

I'd go this way:

#include <functional>

template<typename ReturnType>
class fget
{
    typedef std::function<ReturnType(const char*)> func_type;
    func_type _f;
public:
    fget() = delete;
    fget(const func_type& f) : _f(f) {};
    ReturnType operator()(const char* id) { return _f(id); }
};

double minusPi(const char* id) { (void) id; return -3.14; }
unsigned long long getull(const char* id) { (void) id; return 123456789123456; }


#include <iostream>
int main()
{
    fget<double> mPi{minusPi};
    fget<unsigned long long> ull{getull};

    std::cout << mPi("hello") << std::endl;
    std::cout << ull("hello") << std::endl;
    return 0;
}

Compile & run with:

clang++ -std=c++14 -O2 -Wall -Wextra -pedantic -Werror -pthread main.cpp && ./a.out

Live exemple on Coliru. Output:

-3.14
123456789123456

Upvotes: 0

Simple
Simple

Reputation: 14390

It sounds like you just want template specialisation:

template<typename T>
struct wrapper;

template<>
struct wrapper<int>
{
    static int getVal(char const* id) { /* ... */ }
};

template<>
struct wrapper<widget>
{
    static widget getVal(char const* id) { /* ... */ }
};

Then you would call wrapper<T>::getVal(id).

Upvotes: 3

Related Questions