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.
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>{}, "!");
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With