I´ve created the following Event class:
Event.h
#ifndef EVENT_H
#define EVENT_H
#include<string>
template<typename T>
class Event
{
public:
T fnktptr; //Error: field ‘Event<int()>::fnktptr’ invalidly declared function type
Event();
virtual ~Event();
};
#endif // EVENT_H
Event.cpp
#include "Event.h"
template<typename T>
Event<T>::Event()
{
//ctor
}
template<typename T>
Event<T>::~Event()
{
//dtor
}
// No need to call this TemporaryFunction() function,
// it's just to avoid link error.
void TemporaryFunction ()
{
Event<int> TempObj;
}
Now I tested it with the following code and it works:
Event<int> event;
int t = 5;
event.fnktptr = t;
But finally, I want to use it with a functor like this:
Event<decltype(consumeInt)> event;
event.fnktptr = consumeInt;
But now I get a Error in the Event.h file:
T fnktptr; //Error: field ‘Event<int()>::fnktptr’ invalidly declared function type
Based on your latest comments, I would say a std::function<> is the best way forward. The example code below assumes you just want to call fnktptr and don't care about the result.
#include <functional>
class Event
{
public:
std::function<void ()> fnktptr;
Event();
virtual ~Event();
};
If you need to capture the result, you will not be able to arbitrarily have different returns for each Event object. You either must pick one or use something like boost::variant<>.
template<class T>
class Event
{
public:
std::function<T ()> fnktptr;
Event();
virtual ~Event();
};
This would allow you to create Event<int> objects for instance to use with consumeInt().
Example:
Event<int> event;
event.fnktptr = consumeInt;
Related
I am doing an assignment where I have to connect a member function from the Display class to the Parent template class.
In the parent.hpp header file, I have:
#ifndef parent_hpp
#define parent_hpp
#include <iostream>
using namespace std;
#include <stdio.h>
#include <map>
template <typename... Args>
class Parent
{
public:
Parent();
// Connect a member function to this Parent.
template <typename T> int connect(T *inst, void (T::*func)(Args...));
// Connect a std::function to this Parent.
int connect(std::function<void(Args...)> const& slot);
// Call all connected functions.
void emit(Args... p);
};
#endif /* parent_hpp */
Note that Parent is a template class that several argument types Args. In the main.cpp, I am trying to do the following:
#include "parent.hpp"
#include "interface.hpp"
#include <iostream>
int main() {
Display myDisplay; // Display initialization
Parent<> myParent; // Parent initialization with no arguments
myParent.connect( myDisplay.showMessage()); // Connect showMessage() to myParent
return 0;
}
The idea is that I am trying to connect the showMessage() member function from Display class, which is defined in interface.hpp:
#ifndef interface_hpp
#define interface_hpp
#include <stdio.h>
#include "parent.hpp"
class Display
{
public:
inline void showMessage() const {
std::cout << "Hey there, this is a test!" << std::endl;
}
};
#endif /* interface_hpp */
However, when I am trying to connect the showMessage() member function from Display to Parent, this error shows up: No matching member function for call to 'connect' at the line of myParent.connect( myDisplay.showMessage()). Do you have any idea why this is happening?
There are 2 issues here:
The connect function takes a object pointer and a member function pointer, but you're trying to pass the result of a function call of a void function.
The member function pointer points to a non-const member function, but showMessage is a const member function.
You could fix this by modifying the function signature of connect or overloading the function, and modifying the function call:
template <typename... Args>
class Parent
{
public:
Parent();
// Connect a member function to this Parent.
template <typename T> int connect(T const* inst, void (T::*func)(Args...) const);
// Connect a std::function to this Parent.
int connect(std::function<void(Args...)> const& slot);
// Call all connected functions.
void emit(Args... p);
};
myParent.connect(&myDisplay, &Display::showMessage);
This is about the following setup of an application that uses (abstract) functionality from a *.dll and a static library and which causes read access violation at last (further details are provided below the code):
... static library ...
// InterfaceWrap.h
//-----------
// dummy include
#include <SomeTClass.h>
template<typename T>
class InterfaceWrap
{
std::shared_ptr<SomeTClass<T>> m_somePtr;
public:
InterfaceWrap();
~InterfaceWrap();
void AnyAction();
};
template<typename T>
InterfaceWrap<T>::InterfaceWrap() {
m_somePtr = std::make_shared<SomeTClass<T>>();
}
template<typename T>
void InterfaceWrap<T>::AnyAction() {
m_somePtr->SomeAction();
}
... *.dll ...
// Proc.h
//-----------
// correct forward declaration?
class ThisInterface;
#include <InterfaceWrap.h>
class DLL Proc
{
std::shared_ptr<InterfaceWrap <ThisInterface>> m_interfaceWrapPtr;
public:
Proc();
~Proc();
InterfaceWrap<ThisInterface>* GetPtr();
};
// Proc.cpp
//-----------
// what about forward declaration here?
Proc::Proc() {
m_interfaceWrapPtr = std::make_shared<InterfaceWrap<ThisInterface>>();
}
InterfaceWrap<ThisInterface>* Proc::GetPtr() {
return m_interfaceWrapPtr.get();
}
... the application ...
// main.cpp
//-----------
#include <Proc.h>
// dummy includes
#include <ThisType01.h>
#include <ThisType02.h>
#include <ThisType11.h>
#include <ThisType12.h>
class ThisInterfaceA {
public:
using Type1 = ThisType01;
using Type2 = ThisType02;
};
class ThisInterfaceB { // not needed here but perhaps illustrative
public:
using Type1 = ThisType11;
using Type2 = ThisType12;
};
using ThisInterface = ThisInterfaceA;
int main(int argc, char * argv[])
{
Proc proc;
proc.GetPtr()->AnyAction();
return 0;
}
The crucial intention behind this construction is to keep the Proc and InterfaceWrap classes as abstract as possible, i.e., having them not depending directly on a chosen "interface" like ThisInterfaceA. Moreover I would like to keep the feature, that Proc is not a template class.
Obviously there are problems, of which I'm not sure how to resolve them nicely:
The line using ThisInterface = ThisInterfaceA does not work as it leads to compilation errors for the dll source codes, basically saying that ThisInterface is not known. If however, instead of this line, e.g., ThisInterfaceA is replaced by ThisInterface directly, everything compiles and links fine, at least.
Even if everything compiles and links (compare 1.), there would ultimately occur a read access violation, which concerns m_interfaceWrapPtr or m_somePtr.
What I wonder in particular is, whether properly applied forward declaration is capable of resolving the above issues and allowing to keep the feature that Proc is that abstract (or even more?) and not a template class?
Why not use real interface and DIP:
struct IAnyAction
{
virtual ~IAnyAction() = default;
virtual void AnyAction() = 0;
};
class Proc
{
std::shared_ptr<IAnyAction> m_interface;
public:
Proc(std::shared_ptr<IAnyAction> anyAction) : m_interface(anyAction) {}
IAnyAction* GetPtr() { return m_interface.get(); }
};
template<typename T>
class InterfaceWrap : public IAnyAction
{
std::shared_ptr<SomeTClass<T>> m_somePtr;
public:
InterfaceWrap();
void AnyAction() override { m_somePtr->SomeAction(); }
};
and
using ThisInterface = ThisInterfaceA; // For easy/quick way to change concrete type for interface
int main()
{
Proc proc(std::make_shared<InterfaceWrap<ThisInterface>>());
proc.GetPtr()->AnyAction();
}
In case anyone is interested, in what follows I provide the edited example code (from the beginning) as it finally works for me.
The solution is basically the answer of Jarod42 (Perhaps this overall approach may not be the most elegant one, as pointed out in the other comments. However, I guess some purposes may justify it).
However, there is one little thing added: casted void pointer arguments. To me this turns out useful when extending the original problem towards, e.g., the member AnyAction having an argument of yet unspecified but "known" type.
... static library ...
// InterfaceWrap.h
//-----------
// dummy include
#include <SomeTClass.h>
struct IAnyAction
{
virtual ~IAnyAction() = default;
virtual void AnyAction(void* arg) = 0;
};
template<typename T>
class InterfaceWrap : public IAnyAction
{
std::shared_ptr<SomeTClass<T>> m_somePtr;
public:
InterfaceWrap();
void AnyAction(void* arg);
};
template<typename T>
InterfaceWrap<T>::InterfaceWrap(){
m_somePtr = std::make_shared<SomeTClass<T>>();
}
template<typename T>
void InterfaceWrap<T>::AnyAction(void* arg) override {
auto thisArg = static_cast<T::Type1*>(arg);
m_somePtr->SomeAction(*thisArg);
}
... *.dll ...
// Proc.h
//-----------
#include <InterfaceWrap.h>
class DLL Proc
{
std::shared_ptr<IAnyAction> m_interfaceWrapPtr;
public:
Proc(std::shared_ptr<IAnyAction> interfaceWrapPtr);
~Proc();
IAnyAction* GetPtr();
};
// Proc.cpp
//-----------
Proc::Proc(std::shared_ptr<IAnyAction> interfaceWrapPtr) : m_interfaceWrapPtr(interfaceWrapPtr) {
}
IAnyAction* Proc::GetPtr() {
return m_interfaceWrapPtr.get();
}
... the application ...
// main.cpp
//-----------
#include <Proc.h>
// dummy includes
#include <ThisType01.h>
#include <ThisType02.h>
#include <ThisType11.h>
#include <ThisType12.h>
class ThisInterfaceA {
public:
using Type1 = ThisType01;
using Type2 = ThisType02;
};
class ThisInterfaceB { // not needed here but perhaps illustrative
public:
using Type1 = ThisType11;
using Type2 = ThisType12;
};
using ThisInterface = ThisInterfaceA;
int main(int argc, char * argv[])
{
Proc proc(std::make_shared<InterfaceWrap<ThisInterface>>());
auto type1 = std::make_shared<ThisInterface::Type1*>();
proc.GetPtr()->AnyAction(type1.get());
return 0;
}
I am trying to use template classes to use my functions regardless of the point type. I read the “Writing a new PCL class” tutorial but I have not got it. I will share the simplest class where I am trying to use this technique. Its only function is to create the KDtree of a pointcloud in the correct point of the execution of a parent tree of processes.
KdtreeBuilder_Process.h
#ifndef KDTREEBUILDER_PROCESS_H
#define KDTREEBUILDER_PROCESS_H
#include "ProcessManager/ProcessConcurrent.h" //Parent class
#include <pcl/kdtree/kdtree_flann.h>
class KdtreeBuilder_Process:public ProcessConcurrent
{
public:
KdtreeBuilder_Process(pcl::PointCloud<pcl::PointXYZ>::Ptr inputCloud,pcl::KdTree<pcl::PointXYZ>::Ptr cloudKdtree);
virtual void run(); //method that executed when the process starts
private:
pcl::PointCloud<pcl::PointXYZ>::Ptr mInputCloud;
pcl::KdTree<pcl::PointXYZ>::Ptr mCloudKdtree;
};
#endif // KDTREEBUILDER_PROCESS_H
KdtreeBuilder_Process.cpp
#include "KdtreeBuilder_Process.h"
KdtreeBuilder_Process::KdtreeBuilder_Process(pcl::PointCloud<pcl::PointXYZ>::Ptr inputCloud,pcl::KdTree<pcl::PointXYZ>::Ptr cloudKdtree):
mInputCloud(inputCloud),mCloudKdtree(cloudKdtree)
{
}
void KdtreeBuilder_Process::run(){
mCloudKdtree->setInputCloud(mInputCloud);
}
My intention is to be able to use this class with any point type that contains XYZ coordinates
Thanks for your support.
BR
First of all when dealing with templates you have to accept that all implementation will need to be moved to header files. If you want KdtreeBuilder_Process to be a template that takes class of point in parameter you just need to add appropriate template declaration syntax:
template<class PointType>
class KdtreeBuilder_Process:public ProcessConcurrent
{
public:
If PointCloud class is ready to accept all classes with XYZ coordinates you just need to change your code accordingly
KdtreeBuilder_Process(pcl::PointCloud<PointType>::Ptr inputCloud,pcl::KdTree<PointType>::Ptr cloudKdtree): mInputCloud(inputCloud), mCloudKdtree(cloudKdtree) { }
virtual void run(){
mCloudKdtree->setInputCloud(mInputCloud);
}
private:
pcl::PointCloud<PointType>::Ptr mInputCloud;
pcl::KdTree<PointType>::Ptr mCloudKdtree;
};
Good luck!
I solve the issue. Here is the final solution using only header file:
KdtreeBuilder_Process.h
#ifndef KDTREEBUILDER_PROCESS_H
#define KDTREEBUILDER_PROCESS_H
#include "ProcessManager/ProcessConcurrent.h"
#include "PointDefinitions.h"
#include <pcl/kdtree/kdtree_flann.h>
#include <QDebug>
template<class PointType>
class KdtreeBuilder_Process:public ProcessConcurrent
{
typedef typename pcl::PointCloud<PointType>::Ptr PointCloudPtr;
typedef typename pcl::KdTree<PointType>::Ptr KdTreePtr;
public:
KdtreeBuilder_Process(PointCloudPtr inputCloud,KdTreePtr cloudKdtree): mInputCloud(inputCloud), mCloudKdtree(cloudKdtree) { }
virtual void run(){
mCloudKdtree->setInputCloud(mInputCloud);
}
private:
PointCloudPtr mInputCloud;
KdTreePtr mCloudKdtree;
};
#endif // KDTREEBUILDER_PROCESS_H
The code describes two classes that implement callback function, the function must should be member function in the class parameter that passed in template.
Below the code i attached the relevent error message i get.
a.h
template <class CLASSNAME>
class a
{
public:
typedef void (CLASSNAME::*myFunction)();
a(CLASSNAME& myObject, myFunction callback) :
m_myObject(myObject)
{
m_myFuntion = callback;
}
void update()
{
(m_myObject).*(m_myFuntion);
}
myFunction m_myFuntion;
CLASSNAME& m_myObject;
};
dummy.h
#include <stdio.h>
class dummy
{
public:
dummy()
{
var = 14;
}
void func()
{
printf("func!!");
}
int var;
};
main.cpp
#include <cstdlib>
#include "a.h"
#include "dummy.h"
void main()
{
dummy dum;
a<dummy> avar(dum, &(dummy::func));
avar.update();
system("pause");
}
i am trying to implement the callback function and i get the following error message:
C2298 missing call to bound pointer to member function
what the problem is?
You have a lot of parentheses, they're just not in the right place. The correct syntax for calling a pointer-to-member function is:
void update()
{
(m_myObject.*m_myFuntion)();
}
You are using parentheses in the wrong places:
This:
a<dummy> avar(dum, &(dummy::func));
should be this:
a<dummy> avar(dum, &dummy::func);
And this:
(m_myObject).*(m_myFuntion);
should be:
(m_myObject.*m_myFuntion)();
Live Example
I have an issue when trying to initialize static members of a static class template.
Basically, what I thought this approach would be useful for:
I have a lot of objects, which are of course all of the same Base type but they have differing object types. I just want to manipulate these objects, that's why I decided to use a static template as there are quite a number of different types these object can consist of.
However, for logging and options passing I wanted to add the corresponding members to the template whithout having to write initializers for every derived static class.
Please note that the following code is not actually working, because there is some SDK involved.
I'm just aksing for the right approach, not right code.
Thanks in advance. :)
template.h:
#ifndef _TEMPLATE_H
#define _TEMPLATE_H
#include "stats.h"
template<class T>
class TemplateObj
{
public:
static void SetParameters(const Options& options)
{
T::_options = options; // Is this even possible?
T::Init();
T::DoStuff(_options);
}
protected:
static void Message() { stats.Print("Message from Template static method"); }
static Stats& TemplateObj<T>::stats = Stats::GetInstance(); // This will not work as this is a non-trivial initializer, how to do it correctly? Stats::GetInstance() retrieves a singleton instance
static Options& TemplateObj<T>::_options; // Possible?
};
#endif
derived.h:
#ifndef _DERIVED_H
#define _DERIVED_H
#include "template.h"
class Derived :TemplateObj < Derived >
{
public:
static void Init();
static void DoStuff(Options& options)
};
#endif
derived.cpp:
#include "derived.h"
void Derived::Init()
{
// Init stuff here
TemplateObj::Message(); // Call static method from template directly
}
void Derived::DoStuff(Options& options)
{
// Do something with options
stats.Print("Message from derived static method."); // Access to "stats" here. "stats" should be declared and initialized inside the template.
options.Load(); // Example
}
main.h
#include "derived.h"
main()
{
TemplateObj<Derived>::SetParameters(new Options);
}
Basically, you don't need to put TemplateObj<T>:: before the function definition if it is inside the class definition. The following two are both valid:
template<class T>
class A{
void func( void );
};
template<class T>
void A<T>::func() { /* Okay */ }
template<class T>
class B {
void func( void ){ /* Okay */ }
};
In your case, replace the following static Stats& TemplateObj<T>::stats = Stats::GetInstance(); with static Stats& stat() { return Stats::GetInstance(); }
And the following static Options& TemplateObj<T>::_options; with this static Options& _options;.
On the other hand, replace this T::_options = options; with TemplateObj<T>::_options = options;.