I am not an advanced programmer. The short version of the problem would be: how can I make a template for a global function that calls a pointer to a member function of classes that are only known at runtime (and who have different kind of arguments)?
The function is global and its declaration is this:
template<class T>
const double gExtFunc(const double &x, \
const double &y, \
const double &ep, \
const double &es, \
// function pointer here
const double &a, \
const double &k, \
double &mid_OUT, \
short &i_OUT, \
double &eps_OUT, \
short &trip_OUT);
This gets called inside some (virtual public
) classes. For example (not using ellipsis
):
class DerivedA: virtual public Base
{
public:
void funcA(...)
{
// ...
m_varA = gExtFunc(...);
// ...
}
// ...
const double commonFunc(const double &a, const double &k) const;
};
const double DerivedA::commonFunc(const double &a, const double &k) const
{
// ...
}
The Base
class is just for common variables, mostly. The pointer to function points to commonFunc()
which has the same name in all virtual classes, but different definitions and type of arguments in each. For example, the above DerivedA
uses it with two const double&
arguments, while a DerivedE
with:
const double DerivedE::commonFunc(const int &n, const double &k) const;
Now, I managed to make it work with a lambda function (based on this, when I only had one m_varA
), which meant the function pointer argument of gExtFunc()
was this:
const double gExtFunc(..., std::function<const double(const double&, const double&)> fPnt, ...)
and it was called, for ex. inside DerivedA
, as:
m_varA = gExtFunc(..., [this](const double &a, const double &k){ return commonFunc(a, k); }, ...)
and it worked, but only as long as it was called inside one class, only. As soon as I tried calling it in DerivedE
, for m_varE
, it, too, failed: was not declared in this scope
, pointing to its definition of m_varE
.
I have seen this answer, but that requires me to first create an object, which I can't do. So I tried to go around it and replace the pointer to function argument like this:
template<class T> // first the template, above the function
const double gExtFunc(..., T *t, const double(T::*t)(const double&, const double&) fPnt, ...)
and, inside the definition: t->fPnt(...)
. But how would gExtFunc()
be called? I tried this:
m_varA = gExtFunc(..., new DerivedA(), &DerivedA::commonFunc, ...)
but it fails, was not declared in this scope
, same as above. I am stuck here. If there is an alternative to what I am trying to do, I'm very much willing to change it.
EDIT:
As a temporary, ugly solution, I copied the gExtFunc()
to each class that needs it, trimmed & adjusted, including giving up pointer to function, just a direct call of the member function commonFunc()
. There are only 3 cases, for now, but the future may bring more, which is why I consider this to be ugly and why the question is still valid.
This solution would do it (AClass is a test class):
class AClass
{
private:
std::string s_;
unsigned short a_;
public:
AClass(const std::string& __s, unsigned short __a) : s_(__s), a_(__a) {}
void m_Test(unsigned short __a, const std::string& __s)
{
a_ += __a;
s_.append(__s);
}
unsigned short getA() { return a_; }
std::string getS() { return s_; }
};
template <typename T, typename R, typename ...Args>
R proxycall(T & obj, R (T::*mf)(Args...), Args &&... args)
{
return (obj.*mf)(std::forward<Args>(args)...);
}
template <typename T, T> struct proxy;
template <typename T, typename R, typename ...Args, R(T::*mf)(Args...)>
struct proxy<R(T::*)(Args...), mf>
{
static R call(T & obj, Args &&... args)
{
return (obj.*mf)(std::forward<Args>(args)...);
}
};
int main()
{
AClass a("I ", 2);
proxy<void(AClass::*)(unsigned short, const std::string&), &AClass::m_Test>::call(a, 23 , "am: ");
std::cout << a.getS() << a.getA() << "\n";
std::cin.get();
return 0;
}
I don't remember who wrote this, but it is someone from the forum. Thanks to him.
You could also use polymorphism mechanisms if you can make your commonFunc virtual. I don't know if this will suits your needs, but here is a sample:
class AClass;
double gExtFunc(AClass* __acl, const double& __a, const double& __b, const double& __f);
class AClass
{
private:
const std::string& aClass = "AClass";
protected:
double r_;
public:
AClass() : r_(0) {}
void func_A()
{
r_ = gExtFunc(this, 2.0, 1.5, 300.011);
}
virtual double m_Test(const double& __a, const double& __b)
{
return __a * __b;
}
double getR() { return r_; }
void setR(const double& __r) { r_ = __r; }
virtual const std::string& getClass() { return aClass; }
};
class BClass : virtual public AClass
{
private:
const std::string& bClass = "BClass";
public:
BClass() : AClass() {}
void func_A()
{
r_ = gExtFunc(this, 3.0, 1.5, 311.128);
}
virtual double m_Test(const double& __a, const double& __b)
{
return __a * __b;
}
const std::string& getClass() { return bClass; }
};
double gExtFunc(AClass* __acl, const double& __a, const double& __b, const double& __f)
{
double d = __acl->m_Test(__a, __b);
return d * __f;
}
int main()
{
AClass a;
BClass b;
a.func_A();
b.func_A();
std::cout << a.getR() << "\n" << a.getClass() << "\n\n";
std::cout << b.getR() << "\n" << b.getClass() << "\n";
std::cin.get();
return 0;
}
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