I'm trying to pass a class method to another class method using template, and cannot find any answer on how to do (no C++11, boost ok):
I simplified the core problem to :
class Numerical_Integrator : public Generic Integrator{
template <class T>
void integrate(void (T::*f)() ){
// f(); //already without calling f() i get error
}
}
class Behavior{
void toto(){};
void evolution(){
Numerical_Integrator my_integrator;
my_integrator->integrate(this->toto};
}
I get as error:
error: no matching function for call to ‘Numerical_Integrator::integrate(<unresolved overloaded function type>)’this->toto);
note: no known conversion for argument 1 from ‘<unresolved overloaded function type>’ to ‘void (Behavior::*)()’
Thank you.
Bonus: What about with arguments ?
class Numerical_Integrator{
template <class T, class Args>
double integrate(void (T::*f)(), double a, Args arg){
f(a, arg);
}
}
class Behavior{
double toto(double a, Foo foo){ return something to do};
void evolution(){
Foo foo;
Numerical_Integrator my_integrator;
my_integrator->integrate(this->toto, 5, foo};
}
Your question is not really about passing a class method as part of a template parameter.
Your question is really about correctly invoking a class method.
The following non-template equivalent will not work either:
class SomeClass {
public:
void method();
};
class Numerical_Integrator : public Generic Integrator{
void integrate(void (SomeClass::*f)() ){
f();
}
}
A class method is not a function, and it cannot be invoked as a function, by itself. A class method requires a class instance to be invoked, something along the lines of:
class Numerical_Integrator : public Generic Integrator{
void integrate(SomeClass *instance, void (SomeClass::*f)() ){
(instance->*f)();
}
}
You need to revise the design of your templates, and/or class hierarchies in order to resolve this first. Once you correctly implement your class method invocation, implementing a template should not be an issue.
Related
I have the following code that mixes template and inheritance.
Class Base has some utility function to build items (the work in the sample code), and Child call the work in its implementation of the API call.
In this function
virtual void call() override {
Base<T>::work(); // Problem Here
// work();
}
I try to call work() but got the following error:
test.cc: In member function ‘virtual void Child<T>::call()’:
test.cc:18:2: error: there are no arguments to ‘work’ that depend on a template parameter, so a declaration of ‘work’ must be available [-fpermissive]
So I write Base<T>::work() and makes it work.
Now I have a Grandson class, who want to override the work function. But the override does not work as in Child<T>::call I have explicitly specified calling Base<T>::work(). So what's the correct way to implement Child<T>::call to make the override in Grandson work?
#include <iostream>
template <typename T>
class Base {
protected:
virtual void work() {
T a;
std::cout << "From Base" << '\n';
}
public:
virtual void call() = 0;
};
template <typename T>
class Child : public Base<T> {
public:
virtual void call() override {
Base<T>::work(); // Problem Here
// work();
}
};
template <typename T>
class Grandson : public Child<T> {
protected:
void work() override {
std::cout << "From Grandson" << '\n';
}
};
int main() {
Grandson<int> g;
g.call();
}
Replace Base<T>::work() with this->work().
When you are a template class inheriting from a base class dependent on your template parameter, the compiler doesn't look into your base when it sees something like work(). Instead, you have to tell it that it needs to do that. The easiest way I know of to accomplish that is to prefix the call with this->.
As for why it does not work when you use Base<T>::work(), I am not entirely sure. It's hardcoding it to call the base class implementation, but I'm fairly sure there's a similar syntax that does work.
I am creating an interface file for my library with a method of passing a function pointer. There are 2 approaches:
A: Defined as a member function of a template class
B: Defined as a global
// A:
template<typename T>
using fcnPtr1 = void (T::*)(const int&);
// B:
typedef void(*fcnPtr2)(const int&);
class TestInterface
{
public:
// A: This cause error 'fcnPtr1' is not a type
virtual void setCallback(fcnPtr1 callback) = 0;
// B: This is OK
virtual void setCallback(fcnPtr2 callback) = 0;
};
As of now, approach A gives me an error of "fcnPtr1" is not a type but approach B is ok.
I need to use approach A because don't want my client to define the callback function in global. Any advice?
In your code fcnPtr1 is a template. Since it is a template you need to provide the template type with it to actually instantiate it. This basically undoes what you just did though so it's not helpful
If you need to take arbitray functions but and only want to control the signature then what you can use is a std::function. By using a std::function parameter you can take any type of callable that has a matching function signature. That would turn your code into
class TestInterface
{
public:
virtual void setCallback(std::function<void(const int&)> callback) = 0;
};
How do I do to call a specific method present on all classes from an other (TranslationManager) class ?
I simplified a lot the code. I just want to call the setTranslationText of any class from TranslationManager.
These are to take in consideration:
All classes have a setTranslationText method
We should call setTranslationText of any class from TranslationManager by using the pointer to the class
class Interface
{
...
public:
void setTranslationText(QString translatedString);
}
class AnyOtherInterface
{
...
public:
void setTranslationText(QString translatedString);
}
...
…
Translationmanager::Translationmanager(){
AnyClass = Interface; // Pointer to Interface Class
AnyClass->setTranslatioNText("Text");
AnyClass = AnyOtherInterface; // Pointer to AnyOtherInterface Class
AnyClass->setTranslatioNText("AnotherText");
}
…
You could use a template
template <typename T>
void setTranslationText(T* t, const QString &translatedString)
{
t->setTranslationText(translatedString);
}
That way you wouldn't need an interface class just to inherit for this one (or however many) methods. Then the template would only compile if for a given class instantiation they had a setTranslationText method defined. The way you'd use it is
Translationmanager::Translationmanager()
{
setTranslationText(Interface, "Text"); // Pointer to Interface Class
setTranslationText(AnyOtherInterface, "AnotherText"); // Pointer to AnyOtherInterface Class
}
Adding to Cory's answer: If you're using C strings to initialize QString, you shouldn't depend on the implicit conversion - instead, make your use case explicit:
template <typename T>
void setTranslationText(T* t, const char *translatedString) {
t->setTranslationText(QString::fromUtf8(translatedString));
}
I wasn't precise about what I wanted. I finally found the best solution to my problem: callback.
Solution found on: C++ class member callback simple examples
std::vector<std::function<void(std::string,std::string)>> callbacks;
template<class T> void addTranslationText(T* const object, void(T::* const mf)(std::string,std::string)){
using namespace std::placeholders;
callbacks.emplace_back(std::bind(mf, object, _1, _2));
}
...
// Call callback
callbacks.at(0)(std::string("arg1"), std::string("arg2"));
template <typename... Arguments>
class CCallback
{
public:
template <class TargetClass>
CCallback(TargetClass * target, void (TargetClass::*targetMethod)(Arguments...))
{
}
};
struct TargetClassBase
{
protected:
void f() {}
};
struct TargetClassChild : TargetClassBase
{
void g() {}
void test()
{
CCallback<> callback(this, &TargetClassChild::f);
}
} child;
void main()
{
}
That code doesn't compile in MSVC 2013:
error C2660: 'CCallback<>::CCallback' : function does not take 2
arguments
I don't understand why I get this specific error, and how to make it work. There are no further details about the error logged by the compiler.
And, of course, I can't properly specify that the method belongs to the base class (&TargetClassBase::f)- taking a pointer to a non-public base method is forbidden.
Problem with your code is that compiler cannot deduce template type TargetClass in constructor for CCallback. This is because you pass arguments of types: TargetClassChild* and void (TargetClassBase::*)() to constructor. This is not a typo. Even if you write &TargetClassChild::f this expression still has type: pointer to function returning void in class TargetClassBase and not TargetClassChild as one could expect.
This kind of issues can be solved in two ways:
You could specify template type explicitly, but in this particular case it cannot be done because in C++ there is no way to explicitly pass template parameters to constructors as constructors don't have names (according to note in §14.5.2.5 of c++ standard).
Pass arguments of appropriate types to function. In this case simply cast your function to appropriate type like this static_cast<void (TargetClassChild::*)()>(&TargetClassChild::f)
Expanding on robal's perfectly correct answer, I've rewritten the constructor of my class so that I don't need a manual type cast:
template <class TargetInstanceClass, class TargetMethodClass>
CCallback(TargetInstanceClass * target, void (TargetMethodClass::*targetMethod)(Arguments...))
{
void (TargetInstanceClass::*targetInstanceMethod)(Arguments...) = static_cast<void (TargetInstanceClass::*targetInstanceMethod)(Arguments...)>(targetMethod);
}
I'd like to be able to call any arbitary method (which are generic methods) defined in a derived class from the base class. The base class doesn't know about them. I'd somehow like to get this pointer and the virtual table offset and be able to call it. Class A doesn't actually need to be the base class, it could be a separete class which doesn't know anything about B but needs to call the methods. Is it possible?
class A
{
public:
typedef void (A::*Method)();
void call(Method p)
{
//...
}
};
class B : public A
{
public:
virtual void meth1()
{
}
virtual void meth2()
{
}
virtual void test()
{
call(&TestTask::meth1);
call(&TestTask::meth2);
}
};
Errors:
test.cpp:420:30: error: no matching function for call to ‘B::call(void (TestTask::*)())’
call(&TestTask::meth1);
^
test.cpp:420:30: note: candidate is:
test.cpp:402:10: note: void A::call(A::Method)
void call(Method p)
^
test.cpp:402:10: note: no known conversion for argument 1 from ‘void (TestTask::*)()’ to ‘A::Method {aka void (A::*)()}’
test.cpp:421:30: error: no matching function for call to ‘B::call(void (TestTask::*)())’
call(&TestTask::meth2);
Non-static member functions need an object to act on, so you can't simply call the member-function pointer by itself. You could define a template to call a member of any class, given an object of that class:
template <class Class>
void call(Class & c, void (C::*method)()) {
(c.*method)();
}
If that's not what you want, then you'll need to clarify what you do want.
You can use the CRTP pattern to accomplish what you are trying.
template <typename T> struct A
{
typedef void (T::*Method)();
void call(Method m)
{
(static_cast<T*>(this)->*m)();
}
};
struct B : A<B>
{
void meth1(){}
void meth2(){}
void test()
{
call(&B::meth1);
call(&B::meth2);
}
};