9

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.

Alex Zywicki
  • 2,263
  • 1
  • 19
  • 34

1 Answers1

13

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>{}, "!");
}
Andy Prowl
  • 124,023
  • 23
  • 387
  • 451
  • Is there a way to make it variadic? so that it will work with any number of parameters without having to overload a bunch? – Alex Zywicki Jan 19 '15 at 20:58
  • @AlexZywicki: I added a generalization, although whether or not this is the kind of generalization you are looking for probably depends on your concrete use case for this trait. – Andy Prowl Jan 19 '15 at 21:00
  • I believe that I only need to separate the return type and the arguments from each other. I don't need to access each argument type just the arguments as a list of types if that makes sense. So I would get `foo` and `bar...` from `foo(bar...)` – Alex Zywicki Jan 19 '15 at 21:05
  • @AlexZywicki: Perhaps the last edit to the question goes in that direction? – Andy Prowl Jan 19 '15 at 21:06
  • I was able to use the first example you gave to put together a solution. This comment best explain what I needed to do: "@DieterLücking: I don't (more precisely, no longer) think the OP is looking for a trait. They want to write their own class template and be able to provide a function type as an argument, then disassemble its components." from above. Thanks for the help all. – Alex Zywicki Jan 19 '15 at 21:48
  • I will edit the question later to further explain what I was working on so people can use this as a learning resource if needed – Alex Zywicki Jan 19 '15 at 21:54
  • 1
    @AlexZywicki: Good idea, +1 in advance for the good disposition :) – Andy Prowl Jan 19 '15 at 21:57
  • Is there a way to invoke it? If I get an instance somewhere? – Martin Kosicky Jun 22 '17 at 12:45