Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can you extract types from template parameter function signature

Is there a way that I can extract the types from a function signature in the form foo(bar) and get access to just foo or bar. So if I have the template:

template<typename signiture>
class type{
};

where signiture is foo(bar) and then have a function in the class that reads

foo function(bar b){
    //do stuff
}

I am interfacing with std::function and have found it more convenient to use the foo(bar) syntax instead of using multiple template params like so:

template<typename return_t,param_tps... args>
class type{
    return_t function(param_ps args...){
        return something;
    }
};

Let me know if i can clarify please? Thanks in Advance.

EDIT: for clarification i am interested in a function with N number of parameters to be determined by whatever the specific class instance specifies.

EDIT 2: The code that this question is based off of is as follows:

using std::function;
template <typename signiture>
class Observer;

template <typename return_t, typename ...args_t>
class Observer<return_t(args_t...)> {
protected:
    using signature = return_t(args_t...);
    typedef function<signature> func_t;
    ~Observer(){}
    func_t what_to_do;
public:
    Observer(Subject<signature>& subject,func_t what):what_to_do(what){
        subject.Attach(what_to_do);
    }
    return_t operator()(args_t... args){
        what_to_do(args...);
    }
};

using std::function;
using std::vector;
template <typename signature>
class Subject;

template <typename return_t,typename...param_tps>
class Subject<return_t(param_tps...)> {
    using signature=return_t(param_tps...);
public:
    void Attach(std::function<signature> o){
        obs.push_back(o);
    }
    void operator()(param_tps... params){
        for (typename vector<std::function<signature>>::const_iterator i=obs.begin(); i!=obs.end(); ++i) {
            (*i)(params...);
        }
    }
protected:
    ~Subject(){}
    vector<std::function<signature>> obs;

};

It is an implementation of the Observer pattern that is non-virtual using std::function to glue things together between the two. I wanted to use the foo(bar) syntax because everything it is more conducive to the ease of use of the classes. The issue was converting the function type signature into the return type and the parameter types in order to specify the proper operator() in the subject class so that it can notify the observers with the correct data.

The changes that were made were based upon the example given below as follows:

template<typename t>struct type;
template<typename R,typename... args_t>
struct type<R(args_t...)>{
//use R and args_t as needed
}

Thanks to all who helped.

like image 615
Alex Zywicki Avatar asked Jan 19 '15 20:01

Alex Zywicki


1 Answers

Here is a very basic solution that works for functions accepting one parameter( it seems you are placing this constraint in the question, but a generalized solution is quite easy to provide, as shown in the following):

template<typename S>
struct type; // You can leave this undefined, because the template is
             // supposed to be instantiated with a function type, and
             // that is matched by the specialization below.

template<typename R, typename Arg>
struct type<R(Arg)>
{
    // Just use R and Args as you wish here..
};

Here is a possible example (live demo on Coliru):

#include <type_traits>

template<typename S>
struct signature;

template<typename R, typename Arg>
struct signature<R(Arg)>
{
    using return_type = R;
    using argument_type = Arg;
};

int main()
{
    using ret = signature<void(int)>::return_type;
    using arg = signature<void(int)>::argument_type;

    static_assert(std::is_same<ret, void>{}, "!");
    static_assert(std::is_same<arg, int>{}, "!");
}

In case you are interested in a more general solution for the variadic case, this is probably what you're looking for:

#include <tuple>

struct type; // You can leave this undefined, because the template is
             // supposed to be instantiated with a function type, and
             // that is matched by the specialization below.

template<typename R, typename... Args>
struct type<R(Args...)>
{
    // Just use R and Args... as you with here..
};

And here is a possible usage example (live demo on Coliru):

#include <tuple>
#include <type_traits>

template<typename S>
struct signature;

template<typename R, typename... Args>
struct signature<R(Args...)>
{
    using return_type = R;
    using argument_type = std::tuple<Args...>;
};

int main()
{
    using ret = signature<void(int, double)>::return_type;
    using arg1 = std::tuple_element_t<0, signature<void(int, double)>::argument_type>;
    using arg2 = std::tuple_element_t<1, signature<void(int, double)>::argument_type>;

    static_assert(std::is_same<ret, void>{}, "!");
    static_assert(std::is_same<arg1, int>{}, "!");
    static_assert(std::is_same<arg2, double>{}, "!");
}
like image 75
Andy Prowl Avatar answered Nov 06 '22 01:11

Andy Prowl