问题
I want to have a templated class (wrapper), which can take all possible classes (T) and do stuff (here evaluate) with the member functions of these classes (function).
I found similar requests, which you can see here and here, but neither could satisfy the two conditions below.
Conditions:
Both, a pointer to the instance of the class ( T * ptr) and a pointer to the member function (function) must be accessible within the wrapper class.
The wrapper class shall work with both, const and non-const member functions.
Here a code that works only for non-const:
#include <iostream>
#include <math.h>
template< class T, double (T::*fck) (double) >
struct Wrapper
{
Wrapper( T * ptrT);
double evaluate( double );
protected:
T * myPtrT;
};
template< class T, double (T::*fck) (double) >
Wrapper<T, fck>::Wrapper( T * ptrT) : myPtrT(ptrT) {}
template< class T, double (T::*fck) (double) >
double Wrapper<T, fck>::evaluate( double s )
{ return (myPtrT->*fck)(s); }
struct kernel
{
double gauss( double s )
{
return exp(-0.5*s*s);
}
};
int main()
{
kernel G;
Wrapper<kernel, &kernel::gauss> myKernel ( &G );
std::cout<< myKernel.evaluate(0.0) <<std::endl;
std::cout<< myKernel.evaluate(0.3) <<std::endl;
return 0;
}
回答1:
Is the Wrapper
class strictly necessary? It looks like you're trying to create a generic evaluation mechanism for classes that provide functions with a standard signature: double f(double)
. This is easily solved using std::function
(C++11) or boost::function
(C++03).
Using boost::function
and boost::bind
in C++03:
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <iostream>
#include <math.h>
struct kernel
{
double gauss( double s )
{
return exp(-0.5*s*s);
}
};
int main()
{
kernel G;
typedef boost::function<double (double)> MyWrapper;
MyWrapper w( boost::bind(&kernel::gauss, G, _1) );
std::cout << w(0.0) << std::endl;
std::cout << w(0.3) << std::endl;
return 0;
}
回答2:
All programming problems can be solved by another level of abstraction, except too many levels of abstraction.
template< class T, class Op >
struct Wrapper
{
Wrapper():t(nullptr){}
Wrapper( T* ptrT ):t(ptrT){}
Wrapper( Wrapper const& ) = default;
Wrapper& operator=( Wrapper const& ) = default;
template<class...Args>
auto operator()(Args&&...args) const->decltype( Op{}(std::declval<T*>(),std::declval<Args>()...)) {
return Op{}(t, std::forward<Args>(args)...);
}
T* t;
};
template< class T, bool isConst, class Sig >
struct MemberFunc;
template< class T, class R, class... Args >
struct MemberFunc<T, false, R(Args...) > {
template< R(T::*func)(Args...) >
struct type {
template<class... Ts>
R operator()(T* t, Ts&&...ts) const {
return (t->*func)(std::forward<Ts>(ts)...);
}
};
};
template< class T, class R, class... Args >
struct MemberFunc<T, true, R(Args...) > {
template< R(T::*func)(Args...) const >
struct type {
template<class... Ts>
R operator()(T const* t, Ts&&...ts) const {
return (t->*func)(std::forward<Ts>(ts)...);
}
};
};
struct kernel
{
double gauss( double s )
{
return exp(-0.5*s*s);
}
};
int main()
{
kernel G;
Wrapper<kernel, MemberFunc<kernel, false, double(double)>::type<&kernel::gauss>> myKernel(&G);
std::cout<< myKernel(0.0) <<std::endl;
std::cout<< myKernel(0.3) <<std::endl;
return 0;
}
live example
MemberFunc::type
is basically a compile-time evaluated std::mem_fun
.
Wrapper
now takes a stateless functor as its second argument, which it perfect forwards into. MemberFunc<...>::type<...>
builds such a stateless functor wrapping a member function.
I took the liberty of making it work with arbitrary function signatures, and getting rid of .evaluate
-- we have an invokation operator, if we have an instance whose job it is to be invoked, just invoke it.
Of course, this can also be done with a lambda:
auto myKernel = [G](double s)->double { return G->gauss( s ); };
but the type of myKernel
prevents it from being easily stored and returned in some cases without type-erasing it. Type-erasing it adds runtime indirection, which has runtime costs.
You should still try the type-erased std::function
solution first, and see if it has performance costs, as the code is much, much simpler and easier to read.
来源:https://stackoverflow.com/questions/24888597/template-wrapper-for-const-and-non-const-member-functions-of-arbitrary-classes