I inherited a large rather-old C++98 codebase which is now luckily using C++17. I have an interface in a header file interfaceHeader.h as follows:
struct PluginInterface {
void (*method1)(bool enabled);
void (*method2)(int param1, int param2);
bool (*method3)(const char *path, const int& val);
};
then in another source cpp file:
MyImplementingClass *gClass = new gClass();
void method1(bool enabled) {
gClass->method1(enabled);
}
void method2(int p1, int p2) {
gClass->method2(p1, p2);
}
bool method3(const char *path, const int& val) {
return gClass->method3(path, val);
}
void pupulateInterface(PluginInterface& iface) {
iface.method1 = method1;
iface.method1 = method2;
iface.method1 = method3;
...
}
I don't have control over that global variable nor on the fact that the interface must be a struct of function pointer.
How can I reduce the boilerplate here? I tried using std::bind but it didn't work: a std::function cannot be converted to a C function pointer.
void pupulateInterface2(PluginInterface& iface) {
iface.method1 = [](bool enabled){
gClass->method1(enabled);
};
iface.method2 = [](int param1, int param2){
gClass->method2(param1,param2);
};
iface.method3 = [](const char *path, const int& val){
return gClass->method3(path, val);
};
}
class A{
private:
T x;
public:
A():x(0){}
A(T x1):x(x1){}
void printInfo(const T& a){
cout<<"Succes1"<<endl;
}
};
class B{
private:
int x;
A<int*> var;
public:
B():x(0){}
B(int x1):x(x1){}
void printInfo(const int * a){
var.printInfo(a);
}
};
The probelms is with
void printInfo(const int * a){
var.printInfo(a);
}
It gives an error, saying invalid conversion from ‘const int*’ to ‘int*’
but works with int *a or int *const a
Shouldn't void printInfo in class A look like
void printInfo(const int* a)
Is this correct?
cont int *p, //pointer to constant int
int* const p //constant pointer to int
if thats the case there should be error with
printInfo(int* const a)
not with
printInfo(const int * a)
Shouldn't void printInfo in class A look like
void printInfo(const int* a)
Is this correct?
No, the problem ist that you declare var as A<int*> in B, so A's
void printInfo(const T& a);
is really
void printInfo( int* const& a);
and not
void printInfo( int const* & a);
So, for the call in B to work you need to declare var as A<int const*>. See compiling version here.
void printInfo(const int * a){
Shouldn't void printInfo in class B look like
void printInfo(const int* a)
Is this correct?
Both are equivalent. In many cases, whitespace is not syntactically relevant.
cont int *p, //pointer to constant int
int* const p //constant pointer to int
These are correct.
if thats the case there should be error with
printInfo(int* const a)
not with
printInfo(const int * a)
The error should be when you attempt to implicitly convert a pointer to const into pointer to non-const.
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.
Edit
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;
}
Feel free to downvote my answer if it is wrong. I am just trying to help.
I don't have the mental capacity to read all of that and understand your exact question, but I think I understand the basis of your problem. I am assuming you are doing something like making a function where an argument can vary like:
template <typename T> func(T arg1){}
and somewhere else in code you are expecting that T to be an int or a char * or whatever but you are having trouble converting T to the proper type.
What I would do is work in memory. My function would be something like
enum types {
OBJECT,
INT,
STRING
};
int type;
int addrOfType;
void func(int addr, int typ) {
type = typ;
addrOfType = typ;
}
and to call it do something like
object argument;
func((int)&argument,OBJECT);
and somewhere else in the code you are retrieving the data
switch (type) {
case OBJECT:
object obj = *(object*)addrOfType;
//do whatever with obj
break;
}
I hope that helped. It looked like a tough question so I figured I would attempt to try and help as I sit here bored. Feel free to neg my answer if it is terrible. It is so hard to post on mobile.
I've been assigned the following template:
#include <map>
template <typename T>
class Catalog {
struct Item {
//..
};
std::map<int, Item*> items;
public:
Catalog(void);
Catalog(const Catalog&);
~Catalog(void);
bool IsEmpty(void) const;
int Size() const;
void Add(T*);
T* Remove(T*);
T* Find(T*);
typedef void (T::*pFunc) (const T&);
void Inspection(pFunc) const;
};
Next, there is an abstract Product class and three subclasses:
class Product {
protected:
unsigned int _id;
string _name;
public:
Product(const int& id, const string& name) : _id(id), _name(name) {};
virtual void Action(const Product& p) = 0;
virtual int hashCode() {
return _id*100;
};
unsigned int getId(void) const {return _id;};
string getName(void) const {return _name;};
};
class ProductA : public Product {
public:
ProductA(const int& id, const string& name) : Product(id, name) {};
virtual void Action(const Product& p) {
cout << "ahoj" << endl;
};
};
Finally, class ProductsCatalog that handles a Catalog instance:
class ProductsCatalog {
Catalog<Product> catalog;
public:
//..
void CatalogInspection(void) const {
catalog.Inspection(&Product::Action);
}
};
What I have trouble with is the Inspection method:
template <typename T> void Catalog<T>::Inspection(pFunc p) const {
for (std::map<int, Item*>::const_iterator it=items.begin(); it!=items.end(); ++it) {
it->second->Product->*p(*(it->second->Product));
}
};
I am getting the following error:
error C2064: term does not evaluate to a function taking 1 arguments
I've tried everything I could think of, without success. The following works as intended, but is obviously not abstract enough:
it->second->Product->Action(*it->second->Product);
Did you try
(it->second->Product->*p)(*(it->second->Product));
for calling the method?
The thread Calling C++ class methods via a function pointer seems to be related.
I've searched through Google and stackoverflow and was unable to find something that addresses this situation:
I have a template with a method that takes a function pointer.
The function pointer itself is NOT a template, it's a normal function pointer.
The function pointer, however, has the template args used in its parameters
File name: otherclasses.h
// This class is used as the template parameter
class B
{
public:
B() {}
~B() {}
int getVal() const { return val; }
void setVal(int v) { val = v; }
private:
int val;
};
// This is just a static function
class A
{
public:
static bool someStaticFunction(const B* left, const B* right);
};
inline
bool
A::someStaticFunction(
const B* left,
const B* right)
{
return left->getVal() < right->getVal();
}
File name: templateheader.h
#include "otherclasses.h"
template<typename T>
class theTemplate
{
public:
void insert(T val1, T val2)
{
stuff[0] = val1;
stuff[1] = val2;
}
bool usesSomeStaticFunction(bool (*funcp)(const T, const T))
{
// will return true
return funcp(stuff[0],stuff[1]);
}
private:
T stuff[2];
};
File name: main.cpp
#include "otherclasses.h"
#include "templateheader.h"
#include <stdio.h>
int main()
{
theTemplate<B*> foo;
printf("%d\n", foo.usesSomeStaticFunction(A::someStaticFunction));
return 0;
}
The error from Visual Studio:
error C2664: 'theTemplate<T>::usesSomeStaticFunction' : cannot convert
parameter 1 from 'bool (__cdecl *)(const B *,const B *)' to
'bool (__cdecl *)(const T,const T)'
with
[
T=B *
]
None of the functions with this name in scope match the target type
Two ways around this problem:
Use const void* instead of const T*
Remove const from the parameters of the function pointer and anything that uses it.
Thanks for your help
UPDATE
Turns out there's a better solution - just move the const to the right of B* in the static function:
File name: otherclasses.h EDITED
// This class is used as the template parameter
// This is unchanged.
class B
{
public:
B() {}
~B() {}
int getVal() const { return val; }
void setVal(int v) { val = v; }
private:
int val;
};
// This is just a static function
// This is changed
class A
{
public:
// The "const" is moved to the right side of B*
static bool someStaticFunction(B* const left, B* const right);
};
// This is changed
inline
bool
A::someStaticFunction(
// The function definition must match the function prototype...
B* const left,
B* const right)
{
return left->getVal() < right->getVal();
}
This is because const T becomes T* const, not T const*. One solution is to rework your code to not include the pointer in T (T = B) and include it in the template class instead:
template<typename T>
class theTemplate
{
public:
void insert(T* val1, T* val2)
{
stuff[0] = val1;
stuff[1] = val2;
}
bool usesSomeStaticFunction(bool (*funcp)(const T*, const T*))
{
// will return true
return funcp(stuff[0],stuff[1]);
}
private:
T* stuff[2];
};