I am trying to define a pointer to non-static member function, and pass the pointer along with class object to a template function, which will again send the member function for template struct operation. It keeps giving me type mismatch errors. Please help!
Clarify: 'vecfunc' is a non-static member function of class PTSolver. It takes as input vector and outputs vector. I want to pass a pointer to this vecfunc as a parameter to template function 'newt', which will also pass down to the template struct operation 'fmin().' All throughout the passing processes, I need to give information about PTSolver object 'ptsolver' since it's not a static member function. But I am not able to do this...
template <class T>
struct NRfmin {
VecDoub fvec;
T &func;
int n;
NRfmin(T &funcc) : func(funcc) {}
double operator() (VecDoub_I &x) {
n=x.size();
double sum=0.0;
fvec=func(x);
for (int i = 0;i<n;i++) sum += SQR(fvec[i]);
return 0.5*sum;
}
};
template <class T>
void newt(VecDoub_IO &x, bool &check, T &vecfunc, PTSolver &obj){
NRfmin<T> fmin(obj.*vecfunc);
VecDoub &fvec=fmin.fvec;
f=fmin(x);
...
}
class PTSolver {
public:
PTSolver() = default;
virtual ~PTSolver() = default;
void solve();
VecDoub vecfunc(VecDoub_I);
};
VecDoub PTSolver::vecfunc(VecDoub_I x) {
int n=x.size();
VecDoub results(n);
for (int i=0;i<n;i++) {
results[i]=2.0*x[i];
}
return results;
}
int main() {
VecDoub initGuess(2);
initGuess[0]=4.4;
initGuess[1]=5.5;
bool check;
//function<VecDoub(PTSolver*, VecDoub_I)> Func=&PTSolver::vecfunc;
typedef VecDoub (PTSolver::*PMemFnc)(VecDoub_I x);
PMemFnc Func;
PTSolver ptsolver;
newt<PMemFnc>(initGuess, check, Func, ptsolver);
return 0;
}
You have a type mismatch:
template <class T>
struct NRfmin {
NRfmin(T &funcc) : func(funcc) {}
};
template <class T>
void newt(VecDoub_IO &x, bool &check, T &vecfunc, PTSolver &obj){
NRfmin<T> fmin(obj.*vecfunc);
..
};
In both cases T is a pointer to member function, but you're constructing fmin with something that is definitely not a T& (it isn't even a valid expression). Either you meant to just forward the pointer, in which case:
NRfmin<T> fmin(vecfunc);
Or you want to pass NRfmin a bound functor.
Related
I need to set a function pointer variable which is a method of a template class X to a method of X.
Here is a simple example.
X.h:
template<typename T>
class X {
public:
typedef T (*valproc)(T v);
X(T v);
T add(T v);
T val;
valproc curproc;
};
X.cpp:
#include "X.h"
template<typename T>
X<T>::X(T v) : val(v) {
curproc = &X<T>::add;
}
template<typename T>
T X<T>::add(T v) {
return v+val;
}
int main (int iArgC, char *apArgV[]) {
X<int> *p = new X<int>(3);
return p->curproc(7);
}
When I compile this, I get an error:
$ g++ -c -g -Wall X.cpp
X.cpp: In instantiation of 'X<T>::X(T) [with T = int]':
X.cpp:15:29: required from here
X.cpp:5:13: error: cannot convert 'int (X<int>::*)(int)' to 'X<int>::valproc {aka int (*)(int)}' in assignment
curproc = &X<T>::add;
Apparently int (X< int >::* )(int) is not the same as int (*)(int)
How can I define the correct type?
X<int>::add is a non-static member function. That means that &X<int>::add has the type int(X<int>::*)(int): pointer to non static member function of X<int> taking a single int parameter and returning int. Such a pointer cannot be converted to int(*)(int).
int(X<int>::*)(int) is conceptually more similar to int(*)(X<int>*, int) than it is to int(*)(int) (though the implementation may actually be much different depending on the platform's calling convention or if inheritance is involved). It requires an extra hidden X<int>* parameter: the this pointer.
The easiest way to do what you want would be to use a wrapper method:
template<typename T>
class X {
public:
using valproc = T(X::*)(T v);
X(T v)
: val{v},
proc{&X::add}
{}
T add(T v) { return v + val; }
T curproc(T v) { return (this->*proc)(v); }
T val;
valproc proc;
};
Live Demo
The funky syntax (this->*proc)(i) says "call the member function pointed to by proc on the object pointed to by this with the parameter i".
#include <stdio.h>
template<typename T>
class X {
public:
X(T v);
T add(T v);
T val;
int (X::*curproc)(T v);
};
template<typename T>
X<T>::X(T v) : val(v) {
curproc = &X<T>::add;
}
template<typename T>
T X<T>::add(T v) {
return v+val;
}
int main()
{
printf("Hello World\n");
X<int> *p = new X<int>(3);
printf("%d\n", (p->*(p->curproc))(7));
}
Usualy template classes are defined in the header file.
You can find more information here:
Why can’t I separate the definition of my templates class from its declaration and put it inside a .cpp file?
How can I avoid linker errors with my template functions?
How does the C++ keyword export help with template linker errors?
Change
return p->curproc(7);
to
return (p->*(p->curproc))(7);
*(p->currproc) is the function pointer and that need to be called on p object pointer
For details
C++ function pointer (class member) to non-static member function
So, I have a template class, which must call a callback function at some time. That callback function takes const T template as an argument.
I pass that function's pointer to a template class Boom<void*>. However, the const T argument of that callback is interpreted as just T.
But this is the case only with void*.
The code:
//main.cpp
void kolbek(const void* val)
{
if(val)
printf("Value is: %d\n", *((int*)val));
else
printf("Value ptr = NULL\n");
}
int main()
{
Boom<void*> bomba;
bomba.setCallback(kolbek); //error!
int* nuint = new int(5);
bomba.callCallback((void*)nuint);
delete nuint;
return 0;
}
//boom.h
template<typename T>
class Boom
{
private:
void (*someCallback)(const T) = nullptr;
public:
Boom(){ }
~Boom(){ }
void setCallback(void (*callbk)(const T));
void callCallback(const T val);
};
//boom.cpp
template<typename T>
void Boom<T>::setCallback(void (*callbk)(const T))
{
this->someCallback = callbk;
}
template<typename T>
void Boom<T>::callCallback(const T val)
{
if(someCallback)
(*someCallback)(val);
else
printf("Bad! Callback's NULL!\n");
}
template class Boom<int>;
template class Boom<void*>;
And when trying to compile this, an error is thrown:
error: invalid conversion from 'void (*)(const void*)' to 'void (*)(void*)' [-fpermissive]
error: initializing argument 1 of 'void Boom<T>::setCallback(void (*)(T)) [with T = void*]' [-fpermissive]
How to fix it? Seems like only void* pointers are wrongly interpreted.
Your problem comes from confusing two different consts. This is why it can be helpful to write T const instead of const T - it makes textual substitution not lie to you.
Boom's callback takes a T const which in your instatiation is void* const (not const void*!!): it's a const pointer to non-const void. kolbek's argument takes a void const* - a pointer to const void. Those aren't the same type. You can do a qualification conversion from the former to the latter, but not the other way around (you'd be casting away const!). This is your compiler error.
The simplest solution is not not have Boom add const. It's unnecessary. Use the T as provided and use Boom<const void*>.
In the case mentioned in comment you could create helper struct to make your template dereferenced parameter const:
template<class T>
struct ptr_constantizer {
using type = const T;
};
template<class T>
struct ptr_constantizer<T*> {
using type = const T*;
};
template<typename T>
class Boom
{
private:
void (*someCallback)(typename ptr_constantizer<T>::type) = nullptr;
public:
Boom(){ }
~Boom(){ }
void setCallback(void (*callbk)(typename ptr_constantizer<T>::type)) { }
void callCallback(const T val) { }
};
void foo(const void *ptr) {
}
void fooi(const int non_ptr) {
}
int main() {
Boom<void *> b;
Boom<int> bi;
b.setCallback(&foo);
bi.setCallback(&fooi);
}
The code assumes you are using c++11 as you used nullptr in your example...
When I want to have member function as template argument, is there a way to templetize it without providing Caller type?
struct Foo
{
template <typename Caller, void (Caller::*Func)(int)>
void call(Caller * c) { (c->*Func)(6); }
};
struct Bar
{
void start()
{
Foo f;
f.call<Bar, &Bar::printNumber>(this);
^^^^
}
void printNumber(int i) { std::cout << i; }
};
int main ()
{
Bar b;
b.start();
return 0;
}
when I try
template <void (Caller::*Func)(int), typename Caller>
void call(Caller * c) { (c->*Func)(6); }
and call it like
f.call<&Bar::printNumber>(this);
I am getting Caller is not class... error.
So, is there a way to let compiler deduce the Caller type?
No, not as you want it. Caller could be deduced if
the pointer to member function were an parameter, not a template parameter. Eg:
template <class Caller>
void call(Caller * c, void (Caller::*Func)(int)) { (c->*Func)(6); }
it was known beforehand. For example, you could make the call look like this:
f.arg(this).call<&Bar::printNumber>();
The call function would look similar to this:
template <class Arg>
struct Binder
{
template<void (Arg::*Func)(int)>
void operator()() const {
...
}
};
The arg function would be easy to write (in your case it would return Binder<Bar>, where Bar is deduced from this).
Not very convenient, IMHO.
FastDelegate refers to http://www.codeproject.com/KB/cpp/FastDelegate.aspx, but I don't think it is related.
I have code like following, and got error.
#include <FastDelegate.h>
using namespace fastdelegate;
template <typename T>
T Getter() {}
template <typename T>
void Setter(T) {}
template <typename T>
class Prop
{
public:
typedef FastDelegate0<T> Getter;
typedef FastDelegate1<T> Setter;
Prop(Getter getter, Setter setter) :
m_Getter(getter), m_Setter(setter)
{
}
private:
Getter m_Getter;
Setter m_Setter;
};
template <typename T>
inline Prop<T>* MakeProp(FastDelegate0<T> getter, FastDelegate1<T> setter)
{
return new Prop<T>(getter, setter);
}
static int Target = 0;
int main()
{
FastDelegate0<int> fdGetter(Getter<int>);
Prop<int>* c = MakeProp(fdGetter, Setter<int>);
// ^^^^ error: no matching function for call to 'MakeProp'
}
If changed the main() to:
int main()
{
FastDelegate0<int> fdGetter(Getter<int>);
FastDelegate1<int> fdSetter(Setter<int>);
Prop<int>* c = MakeProp(fdGetter, fdSetter); // It works.
}
or:
int main()
{
FastDelegate0<int> fdGetter(Getter<int>);
Prop<int>* c = MakeProp<int>(fdGetter, Setter<int>); // It works, too.
}
I think, MakeProp() should get the T from fdGetter (which is int, than called the contructor of FastDelegate1<int> automatically. But it did not. Why?
P.S. I would like to save the getter and setter in Prop, any suggestion for this approach is welcome. Maybe it is bad to copy the instance of FastDelegate* during passing arguments in function.
Have you tried
Prop<int>* c = MakeProp(FastDelegate0<int>(Getter<int>), FastDelegate1<int>(Setter<int>));
?
Setter<int> cannot be converted to FastDelegate1<T>!
I have two classes test1 and test2:
struct test1
{
int r;
test1() {}
test1(int value) : r(value) {}
test1 foo() const;
};
struct test2
{
int r;
test2() {}
test2(int value) : r(value) {}
};
template <typename t>
struct data_t
{
static const t one;
};
template <> const test1 data_t<test1>::one = test1(1);
template <> const test2 data_t<test2>::one = test2(1);
then i created a function to do somthing:
template <typename t, const t& value>
t do_somthing()
{ return value; };
the action of do_something is straightforward, it returns a copy of value, so in main function:
int main()
{
test1 r = do_somthing<test1, data_t<test1>::one>();
}
the problem happens when implementing test1::foo
test1 test1::foo() const
{ return do_somthing<test1, *this>(); }
the compiler stops with error:
'this' : can only be referenced inside non-static member functions
with *this it becomes test1 const& which acceptable as 2nd parameter, so why this error?
When you call a template method with explicit mention of parameters like,
do_somthing<test1, data_t<test1>::one>(); //(1) ok
do_somthing<test1, *this>(); // (2) error
then compiler expects that the explicit arguments should be compile time constants. In your (2)nd case, *this is not resolvable to a compile time constant, so you are getting the compiler error.
Change the definition to below:
template <typename t>
t do_somthing(const t& value)
{ return value; };
and now when you call as,
do_somthing<test1>(*this); // (2) ok
it should work. Because, now const t& doesn't need to be a compile time constant, even though it's resolved at compile time.
The compiler tells you exactly why this won't work, 'this' : can only be referenced inside non-static member functions. It's not usable in any other context.
If you want to templatize this function in this manner you have to use a template function that has the ability to deduce the argument type at compile time, like this:
template <class T>
T copy_value(const T& value)
{
return value;
}
class A
{
public:
A clone()
{
return copy_value(*this);
}
};
int main()
{
int x = 999;
int y = copy_value(x);
double d = 9.99;
double e = copy_value(d);
std::string s = "Test";
std::string t = copy_value(s);
return 0;
}
In each of the above examples, the function template is deduced at compile time so the compiler can properly generate the code necessary. Your classes that you use with this template should be appropriately copyable, and copy-constructable.