How do I get the argument types of a function pointer in a variadic template class?
You can write function_traits
class as shown below, to discover the argument types, return type, and number of arguments:
template<typename T>
struct function_traits;
template<typename R, typename ...Args>
struct function_traits<std::function<R(Args...)>>
{
static const size_t nargs = sizeof...(Args);
typedef R result_type;
template <size_t i>
struct arg
{
typedef typename std::tuple_element<i, std::tuple<Args...>>::type type;
};
};
Test code:
struct R{};
struct A{};
struct B{};
int main()
{
typedef std::function<R(A,B)> fun;
std::cout << std::is_same<R, function_traits<fun>::result_type>::value << std::endl;
std::cout << std::is_same<A, function_traits<fun>::arg<0>::type>::value << std::endl;
std::cout << std::is_same<B, function_traits<fun>::arg<1>::type>::value << std::endl;
}
Demo : http://ideone.com/YeN29
How to extract the arguments of a function pointer as type parameter pack?
Both the manual upcast and extracting the parameter types should be
unnecessary.
You can just do this:
template <typename T, typename M, typename ...P>
void invoke(T &&object, M member, P &&... params)
{
(std::forward<T>(object).*member)(std::forward<P>(params)...);
}
Template parameter - function pointer with variadic arguments
You could do the following:
template<typename T, T> struct C;
template<typename T, typename R, typename ...Args, R (T::*F)(Args...)>
struct C<R (T::*)(Args...), F> {
R operator()(T &obj, Args &&... args) {
return (obj.*F)(std::forward<Args>(args)...);
}
};
and then in your program:
struct A {
int foo(int i) { return i; }
};
int main() {
C<int(A::*)(int), &A::foo> c;
A a;
std::cout << c(a, 42) << std::endl;
}
Live Demo
c++ Extract parameter type list from function pointer
The compiler say the you can't define a single type InputArgs
typedef Args InputArgs;
given that Args
is a variadic list.
Maybe you can define a type base on a tuple
using InArgsTuple = std::tuple<Args...>;
so you can extract the single types in Args...
using std::tuple_element
So, with a little template meta-programming, you should be able to write something as
using TplT = MemberFuncArgs<decltype(&TestAppObject::TestMethod)>::InArgsTuple;
std::function<void(TestAppObject*, typename std::tuple_element<Is, TplT>::type ...)>
func = &TestAppObject::TestMethod;
assuming that Is...
is a variadic sequence of template integer values from zero to sizeof...(Args)-1
.
The following is a full compiling C++20 example
#include <tuple>
#include <functional>
struct TestAppObject
{
int TestMethod (char, short, int, long, long long)
{ return 0; }
};
template <typename T>
struct MemberFuncArgs;
template <typename RT, typename Owner, typename ... Args>
struct MemberFuncArgs<RT(Owner::*)(Args...)>
{
static constexpr std::size_t ArgCount = sizeof...(Args);
using ReturnType = RT;
using InArgsTuple = std::tuple<Args...>;
};
int main()
{
using MFA = MemberFuncArgs<decltype(&TestAppObject::TestMethod)>;
using FunT = decltype([]<std::size_t ... Is>(std::index_sequence<Is...>)
-> std::function<void(TestAppObject*,
typename std::tuple_element<Is, MFA::InArgsTuple>::type ...)>
{ return {}; }
(std::make_index_sequence<MFA::ArgCount>{}));
FunT func = &TestAppObject::TestMethod;
}
If you can't use C++20 (so no template lambda and no lambda in not evaluated context) you can substitute the lambda with a traditional template function, only declared (because is used only inside decltype()
.
The following is a full compiling C++14/C++17 example.
#include
#include
struct TestAppObject
{
int TestMethod (char, short, int, long, long long)
{ return 0; }
};
template <typename T>
struct MemberFuncArgs;
template <typename RT, typename Owner, typename ... Args>
struct MemberFuncArgs<RT(Owner::*)(Args...)>
{
static constexpr std::size_t ArgCount = sizeof...(Args);
using ReturnType = RT;
using InArgsTuple = std::tuple<Args...>;
};
template <typename MFA, std::size_t ... Is>
std::function<void(TestAppObject*,
typename std::tuple_element<Is, typename MFA::InArgsTuple>::type ...)>
extra_function (std::index_sequence<Is...>);
int main()
{
using MFA = MemberFuncArgs<decltype(&TestAppObject::TestMethod)>;
using FunT = decltype(extra_function<MFA>
(std::make_index_sequence<MFA::ArgCount>{}));
FunT func = &TestAppObject::TestMethod;
}
Variadic template with member function pointer as parameter
I assume you call the function like this:
int main()
{
int i; char c;
objectsDo(&Object::close, i, c);
}
The problem is that the template arguments are deduced inconsequently:
template <typename ...Args_t>
bool objectsDo(bool (Object::*func)(Args_t...), Args_t&&... args)
Args_t
is deduced as int, char
for the first parameter and int&, char&
for the second. That is because of the internal working of universal references: It works with reference collapsing.
Use another parameter-pack for the trailing parameters :
template <typename ...Args_t, typename... Args>
bool objectsDo(bool (Object::*func)(Args_t...), Args&&... args)
{ /* […] */ }
Or make the trailing parameter a non-deduced context:
template <typename T> struct identity {using type = T;};
template <typename T>
using identity_t = typename identity<T>::type;
template <typename ...Args_t>
bool objectsDo(bool (Object::*func)(Args_t...), identity_t<Args_t>... args){
// […]
}
Pointers to member as variadic template parameters
In C++14, you can use another level of indirection to do that:
struct A {
int a;
float b;
};
template<typename... T>
struct Bar {
template <T A::*... params>
struct Foo {
void Bar(A *obj) {
void *members[] { (&(obj->*params))... };
// ... do something ...
(void)members;
}
};
};
int main() {
A a;
Bar<int, float>::Foo<&A::a, &A::b> foo;
foo.Bar(&a);
}
auto
keyword (introduced with the C++17 for non-type template parameters, as you mentioned) solves more or less this kind of issues. Think of std::integral_constant
and how would it be more user-friendly if you hadn't to specify each time the type as the first argument...
Getting return type of a function pointer in parameter pack and saving it as concatenated tuple with other args
You're evaluating the metafunction too eagerly. The result_of
part is evaluated for the int
too.
You should rearrange the conditional such that what you're selecting is a metafunction instead of a type, and then evaluate that:
template <typename T> struct identity { using type = T; };
template <typename Arg>
using maybe_eval = typename std::conditional_t<
std::is_pointer<Arg>::value && std::is_function<typename std::remove_pointer<Arg>::type>::value,
std::result_of<Arg&&()>,
identity<Arg>
>::type;
using pattern_t = tuple_cat_t<std::tuple<maybe_eval<Args>>...>;
Note that I'm using both conditional_t
and type
Member function pointer wrapper using variadic template (gcc, clang)
When you explicitly specify the types, a parameter pack is greedy. &Foo::bar
will be parsed as part of typename ...Args
, which causes the error.
The correct way to write this is to put it in the function parameter list, instead of a non-type template parameter.
template< class T, typename ...Args>
void member_dispatch(Args&&... args, void(T::*Member)(Args...), void* userdata)
{
T* obj = static_cast<T*>(userdata);
(obj->*Member)(std::forward<Args>(args)...);
}
int main()
{
Foo foo;
member_dispatch<Foo, int>(1, &Foo::bar, &foo);
return 0;
}
A Better Way:
It would be better to take advantage of C++'s template argument deduction. But here you doesn't put the parameter pact at the end of a function parameter list, which is a non-deduced context. So I suggest you re-order it, so that you don't need to specify the template argument:
template<class T, class K, typename ...Args>
void member_dispatch(K T::*ptr, void* userdata, Args&&... args)
{
T* obj = static_cast<T*>(userdata);
(obj->*ptr)(std::forward<Args>(args)...);
}
int main()
{
Foo foo;
member_dispatch(&Foo::bar, &foo, 1);
return 0;
}
Function pointer with variadic template arguments
First, we need a tag and a series of functions to get values from objects based on their types. Simple enough.
template<class T> struct typetag {};
const int& get_type_from_class(const Object* o, typetag<int>) {return o->value;}
const double& get_type_from_class(const Object* o, typetag<double>) {return o->rating;}
const char& get_type_from_class(const Object* o, typetag<char>) {return o->letter;}
const long& get_type_from_class(const Object* o, typetag<long>) {return o->tag;}
The next part is that we need to get types from a list of parameters based on their types, and the first parameter is the default to return if no parameters match. Also not insanely difficult. There's the recursive mismatch case, the recursive match case, and the last-is-match case. Though this appears to have a fair amount of recursion, even the simplest optimizer should be able to inline this to optimal assembly. For reasons I don't understand, these have to be in this exact order.
template<class T>
const T& get_T_by_type(const T& def)
{return def;}
template<class T, class...pRest>
const T& get_T_by_type(const T& def, const T& returnme, const pRest&...rest)
{return returnme;}
template<class T, class p0, class...pRest>
const T& get_T_by_type(const T& def, const p0& discard, const pRest&...rest)
{return get_T_by_type(def, rest...);}
Finally, we call the function. For each ARGS1
, we call get_T_by_type
to get the ARGS2
of the same type, and as the default we use get_type_from_class
to pass the existing value in the class.
template <typename RET, typename... ARGS1, typename... ARGS2>
void Mediator::change (Object* o, RET (Object::*f)(ARGS1...), const ARGS2&... args) {
for (Object* x : objects) {
(x->*f)(
get_T_by_type(get_type_from_class(o, typetag<ARGS1>{}),args...) //pass all args2
... //pass one of that for each args1
);
}
}
Note that I've changed the return type to void
, since you're delegating to calling multiple functions. Alternatively, you could return a vector
of the return results.
http://coliru.stacked-crooked.com/a/36afa072711b0655
Related Topics
How to Construct a Std::String With an Embedded Null
How to Get the Ip Address of a Local Computer
How to Get Error Message When Ifstream Open Fails
Why Is the Destructor of a Future Returned from 'Std::Async' Blocking
How to Print Utf-8 from C++ Console Application on Windows
How to Detect Win32 Process Creation/Termination in C++
Initialize a Const Array in a Class Initializer in C++
Why Is C++11'S Pod "Standard Layout" Definition the Way It Is
How Do Conversion Operators Work in C++
Throw Keyword in Function'S Signature
How to Get the Error Message from the Error Code Returned by Getlasterror()
What Are the Best (Portable) Cross-Platform Arbitrary-Precision Math Libraries
How to Remove an Item from a Stl Vector With a Certain Value