0

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?

Madden
  • 1,024
  • 1
  • 9
  • 27
  • I'm not sure I completely understand what you're trying to do, but maybe you want [`std::type_index`](http://en.cppreference.com/w/cpp/types/type_index)? Why do you need to do this dynamically? – TartanLlama Nov 23 '15 at 12:18
  • Dynamically was perhaps the wrong word to use, basically I just want a convenient way of associating a type with a function, getting the type of a template as it is compiled and then using that association to insert the associated function into the template – Madden Nov 23 '15 at 12:26
  • Which are the intended types for *T*? I mean, it happens to be a primitive type like `int` or you use it with custom types? In the second case, there is one more solution I can put in a response. – skypjack Nov 23 '15 at 12:36
  • The types will (fortunately) just be primitives – Madden Nov 23 '15 at 12:38

4 Answers4

3

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).

Simple
  • 13,992
  • 2
  • 47
  • 47
1

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);
}
eerorika
  • 232,697
  • 12
  • 197
  • 326
0

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
YSC
  • 38,212
  • 9
  • 96
  • 149
0

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);
}
Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141
  • This looks interesting, however my compiler doesn't support template aliasing. I tried to use the trick described here http://stackoverflow.com/questions/14848924/how-to-define-typedef-of-function-pointer-which-has-template-arguments, and then having the map as – Madden Nov 23 '15 at 17:42
  • Sorry, I made a mistake here, there is no template aliasing needed. See my edit. And the type of the map values should be `void(*)(const char*)`. Notice the two stars. Tell me if the error persist. – Guillaume Racicot Nov 23 '15 at 17:52
  • My compiler doesn't support 'using' for aliasing in general it seems, but after changing it to 'typedef void(*type_id_t)();', I am back to the old 'array bound is not an integer constant before ‘]’ token' error in the map assignments – Madden Nov 23 '15 at 18:22
  • I don't know this error. However, what might work is to add the optional `&` with function pointer. So try this: `funcs[&type_id] = ...` – Guillaume Racicot Nov 23 '15 at 18:25