Static member function pointer as template argument - c++

I get this compile error with the latest VC++ compiler (Nov 2012 CTP) when using static member function pointer as template argument:
error C2027: use of undefined type 'wrapper<int (int,int),int A::f1(int,int)>'
But when using free function, everything works ok.
I looked up some similar bugs in g++( pointer to static member function is "invalid" as a template argument for g++ ), but there it explicitly states that argument is invalid. What is so different about static functions?
I'm casting the function to void(*)(void) because construct like <typename T_Ret, typename... T_Args, T_Ret(*)(T_Args...)> don't compile for some other urelated reasons.
struct A
{
static int f1(int a, int b)
{
return a + b;
}
};
int f2(int a, int b)
{
return a + b;
}
template <typename Sig, void(*fnc)(void)>
struct wrapper;
template <void(*fnc)(void), typename T_Ret, typename... T_Args>
struct wrapper<T_Ret (T_Args...), fnc>
{
static bool apply()
{
// get some ints here
int a = 1;
int b = 2;
typedef T_Ret (fnc_ptr*)(T_Args...);
int res = ( (fnc_ptr)fnc )(a, b);
// do smth with result
res;
return true; // or false
}
};
int main()
{
bool res;
res = wrapper<decltype(A::f1), (void(*)(void))A::f1>::apply(); // error
res = wrapper<decltype(f2), (void(*)(void))f2>::apply(); // compiles ok
return 0;
}
EDIT:
Ok, I narrowed the issue to decltype.
When I write the type explicitly, everything works:
res = wrapper<int(int, int), (void(*)(void))A::f1>::apply(); // compiles ok

EDIT:
Looks like it's a compiler bug: http://channel9.msdn.com/Series/C9-Lectures-Stephan-T-Lavavej-Core-C-/STLCCSeries6#c634886322325940618
Workaround:
Change decltype(A::f1) to decltype(&A::f1) which changed its output from int(int, int) to int (__cdecl *)(int,int). And change
template <void(*fnc)(void), typename T_Ret, typename... T_Args>
struct wrapper<T_Ret (T_Args...), fnc>
to
template <void(*fnc)(void), typename T_Ret, typename... T_Args>
struct wrapper<T_Ret (*)(T_Args...), fnc>
Working code:
struct A
{
static int f1(int a, int b)
{
return a + b;
}
};
template <typename Sig, void(*fnc)(void)>
struct wrapper;
template <void(*fnc)(void), typename T_Ret, typename... T_Args>
struct wrapper<T_Ret (*)(T_Args...), fnc>
{
static bool apply()
{
// get some ints here
int a = 1;
int b = 2;
typedef T_Ret (*fnc_ptr)(T_Args...);
int res = ( (fnc_ptr)fnc )(a, b);
// do smth with result
res;
return true; // or false
}
};
int main()
{
bool res;
res = wrapper<decltype(&A::f1), (void(*)(void))A::f1>::apply();
return 0;
}

You could try something like this:
#include <iostream>
using namespace std;
struct A
{
static int f1(int a, int b)
{
return a + b;
}
};
int f2(int a, int b)
{
return a + b;
}
template <typename T, T X>
struct wrapper
{
template <typename... Args>
static bool value(Args... blargs)
{
return X(blargs...) == 3;
}
};
int main()
{
bool res;
res = wrapper<decltype(&A::f1), &A::f1>::value(1,2);
cout << res << endl;
return 0;
}
But seriously, this is so much easier:
#include <iostream>
using namespace std;
int main()
{
bool res;
res = A::f1(a, b) == 3;
cout << res << endl;
return 0;
}

Related

how to write this function in C++ using meta programming

What are you trying to achieve
I want to convert RetType ClassA::MemberFunc(Args...) to mem_fn(&ClassA::MemberFunc) but it is like a function in order to avoid write lambda or function for every member functions
What did you get out (include error messages)
no matching function for call to ‘regisAdd(std::_Mem_fn<int (ABC::*)(int, int)>)’
Here is my code.
#include <functional>
#include <iostream>
using namespace std;
struct ABC {
int value;
int add(int a, int b) {
return a + b * value;
}
int other(int a) {
return a * value;
}
};
int doAdd(void* data, int a, int b) {
ABC* p = (ABC*)data;
return p->add(a, b);
}
typedef int (*TYPE_ADD)(void* data, int a, int b);
TYPE_ADD gAdd = nullptr;
void regisAdd(TYPE_ADD a) {
gAdd = a;
}
void callAdd() {
if (!gAdd) return;
ABC abc;
abc.value = 10;
cout << gAdd(&abc, 1, 2) << endl;
}
typedef int (*TYPE_OTHER)(void* data, int a);
TYPE_OTHER gOther = nullptr;
void regisOther(TYPE_OTHER a) {
gOther = a;
}
void callOther() {
if (!gOther) return;
ABC abc;
abc.value = 10;
cout << gOther(&abc, 12) << endl;
}
int main() {
regisAdd(doAdd); // this is GOOD
callAdd(); // call
regisAdd([](void* data, int a, int b) { // < this is also GOOD
return static_cast<ABC*>(data)->add(a, b); // < GOOD
}); // < GOOD
callAdd(); // call
// how to write a general function work like mem_fn
// to avoid write doAdd and lambda for every function signatures
// regisAdd(mem_fn(&ABC::add));
// regisOther(mem_fn(&ABC::other));
// callAdd();
return 0;
}
As I understand, you want something like:
template <auto mem> // C++17, else <typename T, T mem>
struct mem_to_func;
template <typename C, typename Ret, typename ... Args,
Ret (C::*m)(Args...)>
struct mem_to_func<m>
{
static Ret func_ptr(C* c, Args... args)
{
return (c->*m)(std::forward<Args>(args)...);
}
static Ret func_ref(C& c, Args... args)
{
return (c.*m)(std::forward<Args>(args)...);
}
static Ret func_voidp(void* p, Args... args)
{
auto* c = static_cast<C*>(p);
return (c->*m)(std::forward<Args>(args)...);
}
};
template <typename C, typename Ret, typename ... Args,
Ret (C::*m)(Args...) const>
struct mem_to_func<m>
{
static Ret func(const C* c, Args... args)
{
return (c->*m)(std::forward<Args>(args)...);
}
static Ret func_ref(const C& c, Args... args)
{
return (c.*m)(std::forward<Args>(args)...);
}
static Ret func_voidp(const void* p, Args... args)
{
const auto* c = static_cast<const C*>(p);
return (c->*m)(std::forward<Args>(args)...);
}
};
// Others specializations for combination with
// - volatile,
// - reference to this,
// - and C-ellipsis...
and then
regisAdd(mem_to_func<&ABC::add>::func_voidp);

Get function return type in template

How can I get return type for any function passed to template?
I don't know how to convert between template<typename T> and template<typename Result, typename Args...>:
template<typename T>
void print_name(T f)
{
static_assert(internal::is_function_pointer<T>::value
|| std::is_member_function_pointer<T>::value,
"T must be function or member function pointer.");
typename decltype(f(...)) Result; // ???
typename std::result_of<T>()::type Result; // ???
printf("%s\n", typeid(Result).name());
}
void f_void() {}
int f_int(int x) { return 0; }
float f_float(int x, int y) { return 0.f; }
struct X { int f(int x, float y) { return 0; } };
int main()
{
print_name(f_void);
print_name(f_int);
print_name(f_float);
print_name(&X::f);
return 0;
}
How can i get type Result inside function print_name?
A possible solution is using a function declaration that extracts the return type as well as all the parameters. You don't have even to define it.
It follows a minimal, working example:
#include<typeinfo>
#include<cstdio>
template<typename R, typename... A>
R ret(R(*)(A...));
template<typename C, typename R, typename... A>
R ret(R(C::*)(A...));
template<typename T>
void print_name(T f)
{
printf("%s\n", typeid(decltype(ret(f))).name());
}
void f_void() {}
int f_int(int x) { return 0; }
float f_float(int x, int y) { return 0.f; }
struct X { int f(int x, float y) { return 0; } };
int main()
{
print_name(f_void);
print_name(f_int);
print_name(f_float);
print_name(&X::f);
return 0;
}
As you can see, the declarations provided for ret has the same return type of the submitted function or member function.
A decltype does the rest.
as of C++ 20, the answer is
std::invoke_result_t<T>

How do I make this template argument variadic?

Say I have a template declaration like this:
template <class A, class B, class C = A (&)(B)>
How would I make it so that I could have a variable amount of objects of type C? Doing class C ...c = x won't work because variadic template arguments can't have default values. So this is what I've tried:
template <typename T>
struct helper;
template <typename F, typename B>
struct helper<F(B)> {
typedef F (&type)(B);
};
template <class F, class B, typename helper<F(B)>::type ... C>
void f(C ...c) { // error
}
But up to the last part I get error messages. I don't think I'm doing this right. What am I doing wrong here?
I think you can use the following approach. First, some machinery for type traits. This allows you to determine if the types in an argument pack are homogeneous (I guess you want all functions to have the same signature):
struct null_type { };
// Declare primary template
template<typename... Ts>
struct homogeneous_type;
// Base step
template<typename T>
struct homogeneous_type<T>
{
using type = T;
static const bool isHomogeneous = true;
};
// Induction step
template<typename T, typename... Ts>
struct homogeneous_type<T, Ts...>
{
// The underlying type of the tail of the parameter pack
using type_of_remaining_parameters = typename
homogeneous_type<Ts...>::type;
// True if each parameter in the pack has the same type
static const bool isHomogeneous =
is_same<T, type_of_remaining_parameters>::value;
// If isHomogeneous is "false", the underlying type is a fictitious type
using type = typename conditional<isHomogeneous, T, null_type>::type;
};
// Meta-function to determine if a parameter pack is homogeneous
template<typename... Ts>
struct is_homogeneous_pack
{
static const bool value = homogeneous_type<Ts...>::isHomogeneous;
};
Then, some more type traits to figure out the signature of a generic function:
template<typename T>
struct signature;
template<typename A, typename B>
struct signature<A (&)(B)>
{
using ret_type = A;
using arg_type = B;
};
And finally, this is how you would define your variadic function template:
template <typename... F>
void foo(F&&... f)
{
static_assert(is_homogeneous_pack<F...>::value, "Not homogeneous!");
using fxn_type = typename homogeneous_type<F...>::type;
// This was template parameter A in your original code
using ret_type = typename signature<fxn_type>::ret_type;
// This was template parameter B in your original code
using arg_type = typename signature<fxn_type>::arg_type;
// ...
}
Here is a short test:
int fxn1(double) { }
int fxn2(double) { }
int fxn3(string) { }
int main()
{
foo(fxn1, fxn2); // OK
foo(fxn1, fxn2, fxn3); // ERROR! not homogeneous signatures
return 0;
}
Finally, if you need an inspiration on what to do once you have that argument pack, you can check out a small library I wrote (from which part of the machinery used in this answer is taken). An easy way to call all the functions in the argument pack F... f is the following (credits to #MarkGlisse):
initializer_list<int>{(f(forward<ArgType>(arg)), 0)...};
You can easily wrap that in a macro (just see Mark's answer to the link I posted).
Here is a complete, compilable program:
#include <iostream>
#include <type_traits>
using namespace std;
struct null_type { };
// Declare primary template
template<typename... Ts>
struct homogeneous_type;
// Base step
template<typename T>
struct homogeneous_type<T>
{
using type = T;
static const bool isHomogeneous = true;
};
// Induction step
template<typename T, typename... Ts>
struct homogeneous_type<T, Ts...>
{
// The underlying type of the tail of the parameter pack
using type_of_remaining_parameters = typename
homogeneous_type<Ts...>::type;
// True if each parameter in the pack has the same type
static const bool isHomogeneous =
is_same<T, type_of_remaining_parameters>::value;
// If isHomogeneous is "false", the underlying type is a fictitious type
using type = typename conditional<isHomogeneous, T, null_type>::type;
};
// Meta-function to determine if a parameter pack is homogeneous
template<typename... Ts>
struct is_homogeneous_pack
{
static const bool value = homogeneous_type<Ts...>::isHomogeneous;
};
template<typename T>
struct signature;
template<typename A, typename B>
struct signature<A (&)(B)>
{
using ret_type = A;
using arg_type = B;
};
template <typename F>
void foo(F&& f)
{
cout << f(42) << endl;
}
template <typename... F>
void foo(typename homogeneous_type<F...>::type f, F&&... fs)
{
static_assert(is_homogeneous_pack<F...>::value, "Not homogeneous!");
using fxn_type = typename homogeneous_type<F...>::type;
// This was template parameter A in your original code
using ret_type = typename signature<fxn_type>::ret_type;
// This was template parameter B in your original code
using arg_type = typename signature<fxn_type>::arg_type;
cout << f(42) << endl;
foo(fs...);
}
int fxn1(double i) { return i + 1; }
int fxn2(double i) { return i * 2; }
int fxn3(double i) { return i / 2; }
int fxn4(string s) { return 0; }
int main()
{
foo(fxn1, fxn2, fxn3); // OK
// foo(fxn1, fxn2, fxn4); // ERROR! not homogeneous signatures
return 0;
}
template <typename T>
struct helper;
template <typename F, typename B>
struct helper<F(B)> {
typedef F (*type)(B);
};
template<class F, class B>
void f()
{
}
template <class F, class B, typename... C>
void f(typename helper<F(B)>::type x, C... c)
{
std::cout << x(B(10)) << '\n';
f<F,B>(c...);
}
int identity(int i) { return i; }
int half(int i) { return i/2; }
int square(int i) { return i * i; }
int cube(int i) { return i * i * i; }
int main()
{
f<int,int>(identity,half,square,cube);
}
Here's a modified version that can deduce types:
template<class F, class B>
void f(F(*x)(B))
{
x(B());
}
template <class F, class B, typename... C>
void f(F(*x)(B), C... c)
{
f(x);
f<F,B>(c...);
}
int identity(int i) { return i; }
int half(int i) { return i/2; }
int square(int i) { return i * i; }
int cube(int i) { return i * i * i; }
int string_to_int(std::string) { return 42; }
int main()
{
f(identity,half,square,cube);
// f(identity,half,string_to_int);
}

set a specific member with template parameter

let's say I have this:
struct myStruct {
int A;
int B;
}
Is it possible to set a specific member via a template parameter like this?
void setTo10<?? member>(myStruct& obj) {
obj.member = 10;
}
//usage:
setTo10<"member A">(obj);
I know it's possible with a macro but how about a template?
thanks
Something like this?
struct myStruct {
int A;
int B;
};
template <typename T, typename V>
void set(T& t, V T::*f, V v)
{ t.*f = v; }
int main()
{
myStruct m;
set(m, &myStruct::A, 10);
std::cout << m.A << '\n';
}
This solution allows to select a member via a compile-time index (which could be computed via another compile-time expression):
struct myStruct {
int A;
int B;
};
template <int n1, int n2>
struct SetOnEqual
{
static void set(int& var, int val)
{} // default: do nothing
};
template<int n>
struct SetOnEqual<n, n>
{
static void set(int& var, int val)
{
var = val;
}
};
template <int n>
void setTo10(myStruct& s)
{
SetOnEqual<n,0>::set(s.A, 10);
SetOnEqual<n,1>::set(s.B, 10);
}
Then the following code
#include <stdio.h>
int main()
{
myStruct s;
s.A = s.B = 0;
setTo10<0>(s); // sets s.A
printf("s=(%d,%d)\n", s.A, s.B);
setTo10<1>(s); // sets s.B
printf("s=(%d,%d)\n", s.A, s.B);
return 0;
}
gives the output
s=(10,0)
s=(10,10)

c++0x: overloading on lambda arity

I'm trying to create a function which can be called with a lambda that takes either 0, 1 or 2 arguments. Since I need the code to work on both g++ 4.5 and vs2010(which doesn't support variadic templates or lambda conversions to function pointers) the only idea I've come up with is to choose which implementation to call based on arity. The below is my non working guess at how this should look. Is there any way to fix my code or is there a better way to do this in general?
#include <iostream>
#include <functional>
using namespace std;
template <class Func> struct arity;
template <class Func>
struct arity<Func()>{ static const int val = 0; };
template <class Func, class Arg1>
struct arity<Func(Arg1)>{ static const int val = 1; };
template <class Func, class Arg1, class Arg2>
struct arity<Func(Arg1,Arg2)>{ static const int val = 2; };
template<class F>
void bar(F f)
{
cout << arity<F>::val << endl;
}
int main()
{
bar([]{cout << "test" << endl;});
}
A lambda function is a class type with a single function call operator. You can thus detect the arity of that function call operator by taking its address and using overload resolution to select which function to call:
#include <iostream>
template<typename F,typename R>
void do_stuff(F& f,R (F::*mf)() const)
{
(f.*mf)();
}
template<typename F,typename R,typename A1>
void do_stuff(F& f,R (F::*mf)(A1) const)
{
(f.*mf)(99);
}
template<typename F,typename R,typename A1,typename A2>
void do_stuff(F& f,R (F::*mf)(A1,A2) const)
{
(f.*mf)(42,123);
}
template<typename F>
void do_stuff(F f)
{
do_stuff(f,&F::operator());
}
int main()
{
do_stuff([]{std::cout<<"no args"<<std::endl;});
do_stuff([](int a1){std::cout<<"1 args="<<a1<<std::endl;});
do_stuff([](int a1,int a2){std::cout<<"2 args="<<a1<<","<<a2<<std::endl;});
}
Be careful though: this won't work with function types, or class types that have more than one function call operator, or non-const function call operators.
I thought the following would work but it doesn't, I'm posting it for two reasons.
To save people the time if they had the same idea
If someone knows why this doesn't work, I'm not 100% sure I understand (although I have my suspicions)
Code follows:
#include <iostream>
#include <functional>
template <typename Ret>
unsigned arity(std::function<Ret()>) { return 0; }
template <typename Ret, typename A1>
unsigned arity(std::function<Ret(A1)>) { return 1; }
template <typename Ret, typename A1, typename A2>
unsigned arity(std::function<Ret(A1, A2)>) { return 2; }
// rinse and repeat
int main()
{
std::function<void(int)> f = [](int i) { }; // this binds fine
// Error: no matching function for call to 'arity(main()::<lambda(int)>)'
std::cout << arity([](int i) { });
}
Compile time means of obtaining the arity of a function or a function object, including that of a lambda:
int main (int argc, char ** argv) {
auto f0 = []() {};
auto f1 = [](int) {};
auto f2 = [](int, void *) {};
std::cout << Arity<decltype(f0)>::value << std::endl; // 0
std::cout << Arity<decltype(f1)>::value << std::endl; // 1
std::cout << Arity<decltype(f2)>::value << std::endl; // 2
std::cout << Arity<decltype(main)>::value << std::endl; // 2
}
template <typename Func>
class Arity {
private:
struct Any {
template <typename T>
operator T ();
};
template <typename T>
struct Id {
typedef T type;
};
template <size_t N>
struct Size {
enum { value = N };
};
template <typename F>
static Size<0> match (
F f,
decltype(f()) * = nullptr);
template <typename F>
static Size<1> match (
F f,
decltype(f(Any())) * = nullptr,
decltype(f(Any())) * = nullptr);
template <typename F>
static Size<2> match (
F f,
decltype(f(Any(), Any())) * = nullptr,
decltype(f(Any(), Any())) * = nullptr,
decltype(f(Any(), Any())) * = nullptr);
public:
enum { value = Id<decltype(match(static_cast<Func>(Any())))>::type::value };
};
This way works:
template<typename F>
auto call(F f) -> decltype(f(1))
{
return f(1);
}
template<typename F>
auto call(F f, void * fake = 0) -> decltype(f(2,3))
{
return f(2,3);
}
template<typename F>
auto call(F f, void * fake = 0, void * fake2 = 0) -> decltype(f(4,5,6))
{
return f(4,5,6);
}
int main()
{
auto x1 = call([](int a){ return a*10; });
auto x2 = call([](int a, int b){ return a*b; });
auto x3 = call([](int a, int b, int c){ return a*b*c; });
// x1 == 1*10
// x2 == 2*3
// x3 == 4*5*6
}
It works for all callable types (lambdas, functors, etc)