C++ class member callback and external library - boost

I would like to solve this issue about class member function callback.
Imagine you have a function from an external library (which cannot be modified!) like this:
void fortranFunction(int n, void udf(double*) );
I would like to pass as the udf function above a function member of an existing class. Please look at the following code:
// External function (tipically from a fortran library)
void fortranFunction(int n, void udf(double*) )
{
// do something
}
// User Defined Function (UDF)
void myUDF(double* a)
{
// do something
}
// Class containing the User Defined Function (UDF)
class myClass
{
public:
void classUDF(double* a)
{
// do something...
};
};
int main()
{
int n=1;
// The UDF to be supplied is myUDF
fortranFunction(n, myUDF);
// The UDF is the classUDF member function of a myClass object
myClass myClassObj;
fortranFunction(n, myClassObj.classUDF); // ERROR!!
}
The last line of the code above results in a compilation error, because you cannot declare the classUDF member function as a static function.
Do you know if it is possible to solve this issue?
Probably Boost libraries could help me, but I do not know how (please consider that fortranFunction cannot be modified because is from an external library).
Thanks a lot!
Alberto

I don't understand, why can't you declare classUDF as static like this
class myClass {
public:
static void classUDF(double *a) {
...
}
};
and then pass it like
fortranFunction(n, myClass::classUDF);

You might try that solution (a little bit hacky, but I think, it should work for you):
void fortranFunction(int n, void udf(double*))
{
double d = static_cast<double>(n);
udf(&d);
}
class myClass {
public:
void classUDF(double* a) {
}
};
#ifdef _MSC_VER
#define THREADLOCALSTATIC __declspec(thread) static
#define THREADLOCAL
#else
#define THREADLOCALSTATIC static ___thread
#define THREADLOCAL ___thread
#endif
struct _trampolinebase {
THREADLOCALSTATIC _trampolinebase* current_trampoline;
};
THREADLOCAL _trampolinebase* _trampolinebase::current_trampoline = 0;
#undef THREADLOCAL
#undef THREADLOCALSTATIC
template<class CBRET, class CBARG1, class T>
struct _trampoline1 : _trampolinebase
{
typedef CBRET (T::*CALLBACKFN)(CBARG1);
_trampoline1(T& target, CALLBACKFN& callback)
: callback_(callback)
, target_(target)
{
assert(current_trampoline == 0);
current_trampoline = this;
}
static CBRET callback(CBARG1 a1) {
_trampoline1* this_ = static_cast<_trampoline1*>(current_trampoline);
current_trampoline = 0;
return this_->trampoline(a1);
}
private:
CBRET trampoline(CBARG1 a1) {
return (target_.*callback_)(a1);
}
CALLBACKFN& callback_;
T& target_;
};
template<class FRET, class FARG1, class CBRET, class CBARG1, class T, class F>
FRET call1_1(T& target, CBRET (T::*callback)(CBARG1), F& fortranfunction, FARG1 a)
{
typedef typename _trampoline1<CBRET, CBARG1, T> trampoline;
trampoline t(target, callback);
return fortranFunction(a, trampoline::callback);
}
int main()
{
int n=1;
myClass myClassObj;
call1_1<void,int,void,double*>(myClassObj, &myClass::classUDF, fortranFunction, 1);
}
With the 'threadlocal' stuff, this will work in multithreaded calls, too. You may omit that, if you don't use a multithreaded environment. It also works with recursive calls (e.g. if the callback calls another fortran function).
This solution works only for one single argument plus callback for the fortran function and one single argument in the callback function itself, but you should be able to extend it easily. This is also, why I called it 'call1_1' (fortran function with 1 argument, callbackfunction with 1 argument). FRET is the return type of the fortran function, FARG1 the type of the first argument (int in this case). CBRET and CBARG are the same for the callback function.
Before the fortran function is actually called, the target object is stored within a global (thread-local) variable. The fortran function calls a static callback function, which finally calls your member function.
I invented the trampolinebase to instantiate the static member, I could also have used a global variable for that (but for some reason, I don't like global variables too much) ;-)

Related

Encounter std::bad_weak_ptr exception after converting a unique_ptr created from a factory method to shared_ptr and using shared_from_this

In summary, I have a class inherited from std::enabled_shared_from_this, and there is a factory method return an std::unique_ptr of it. In another class, I convert the std::unique_ptr of the previous class object to std::shared_ptr, and then I call shared_from_this(), which then throws std::bad_weak_ptr. The code is shown below:
#include <memory>
#include <iostream>
struct Executor;
struct Executor1 {
Executor1(const std::shared_ptr<Executor>& executor,
int x): parent(executor) {
std::cout << x << std::endl;
}
std::shared_ptr<Executor> parent;
};
struct Backend {
virtual ~Backend() {}
virtual void run() = 0;
};
struct Executor: public Backend, public std::enable_shared_from_this<Executor> {
const int data = 10;
virtual void run() override {
Executor1 x(shared_from_this(), data);
}
};
// std::shared_ptr<Backend> createBackend() {
std::unique_ptr<Backend> createBackend() {
return std::make_unique<Executor>();
}
class MainInstance {
private:
std::shared_ptr<Backend> backend;
public:
MainInstance(): backend(createBackend()) {
backend->run();
}
};
int main() {
MainInstance m;
return 0;
}
Indeed changing std::unique_ptr<Backend> createBackend() to std::shared_ptr<Backend> createBackend() can solve the problem, but as I understand, in general, the factory pattern should prefer return a unique_ptr. Considering a good pratice of software engineering, is there a better solution?
[util.smartptr.shared.const]/1 In the constructor definitions below, enables shared_from_this with p, for a pointer p of type Y*, means that if Y has an unambiguous and accessible base class that is a specialization of enable_shared_from_this (23.11.2.5), then [magic happens that makes shared_from_this() work for *p - IT]
template <class Y, class D> shared_ptr(unique_ptr<Y, D>&& r);
[util.smartptr.shared.const]/29 Effects: ... equivalent to shared_ptr(r.release(), r.get_deleter())...
template<class Y, class D> shared_ptr(Y* p, D d);
[util.smartptr.shared.const]/10 Effects: ... enable shared_from_this with p
Your example executes std::shared_ptr<Backend>(uptr) where uptr is std::unique_ptr<Backend>, which is equivalent to std::shared_ptr<Backend>(p, d) where p is of type Backend*. This constructor enables shared_from_this with p - but that's a no-op, as Backend doesn't have an unambiguous and accessible base class that is a specialization of enable_shared_from_this
In order for Executor::enable_from_this to work, you need to pass to a shared_ptr constructor a pointer whose static type is Executor* (or some type derived therefrom).
Ok, I find a simple solution, that is, using auto as the return type of the factory function, instead of std::unique_ptr or std::shared_ptr, and keeping std::make_unique inside the factory function. The factory function createBackend should be:
auto createBackend() {
return std::make_unique<Executor>();
}
In this case, the return type can be automatically determined, although I don't know how it works exactly. This code can return either unique_ptr or shared_ptr, which should be better than just using shared_ptr. I tested clang and gcc, and both of them worked, but I am still not sure if this is gauranteed by the type deduction and the implicit conversion.
Update:
Actually, I have found that auto deduces the return type above as std::unique_ptr<Executor> instead of std::unique_ptr<Backend>, which might be the reason why the code works. But using auto has an issue: if you return the smart pointer in an if-else block, where the return type varies depending on some parameters, then auto cannot determine the type. For example:
std::unique_ptr<Backend> createBackend(int k = 0) {
if (k == 0) {
return std::make_unique<Executor>();
}
else {
return std::make_unique<Intepreter>();
}
}
Here, both Executor and Intepreter derive from Backend. I think a correct solution includes:
Inherit Backend instead of its derived classes from std::enable_shared_from_this;
Use dynamic_pointer_cast<Derived class> to cast the shared_ptr to derived class after shared_from_this.
The full code is listed in:
https://gist.github.com/HanatoK/8d91a8ed71271e526d9becac0b20f758

std::function and friend function

In this example, I have a pointer of function (std::function) as an attribute of my class. So I can associate any function of the form void myFunction(void) to my class.
#include <iostream>
#include <functional>
class Example{
private:
int variable=4;
public:
std::function<void(void)> myNonMemberFunction;
Example(void){
}
Example(std::function<void(void)> MyNonMemberFunction){
myNonMemberFunction=MyNonMemberFunction;
}
};
void PrintPlop(){
std::cout<<"plop"<<std::endl;
}
int main() {
Example example(PrintPlop);
example.myNonMemberFunction();
}
Now, I want to do the same but with a function which has accessed to the class attribute like a friend function or a class-member function. How can I do this?
So you want any function you pass to the constructor become a friend?
In the strict sense it is impossible, because the access level (friend or not) is a compile-time issue, and which value is passed to the constructor, generally speaking, is determined only in run-time.
So you either declare all the relevant functions as friends (why not just make them methods in this case?) or pass the private members to them as additional parameters. Like this:
class Example{
private:
int variable=4;
std::function<void(int)> myNonMemberFunction;
public:
Example(void){
}
Example(std::function<void(int)> MyNonMemberFunction){
myNonMemberFunction=MyNonMemberFunction;
}
void callMyNonMemberFunction() {
myNonMemberFunction(variable);
}
};
void PrintPlop(int v){
std::cout<<"plop"<< v << std::endl;
}
int main() {
Example example(PrintPlop);
example.callMyNonMemberFunction();
}

Linker refers to, supposedly, undefined reference to vtable

I am trying to use an abstract class to represent a common base for subtypes. However, it (the linker it seems) keeps moaning about vtables and undefined references no matter what I do. Judging by the error messages, the problem must be related to the destructors in some way. Wierdldy enough, it keeps talking about a
"undefined reference to 'AbstractBase::~AbstractBase()'"
in child.cpp which makes no sense.
Like last time, I can't actually show my code, so here is an example that in essence does the same thing:
First the abstract class, "AbstractBase.h":
#ifndef ABSTRACTBASE
#define ABSTRACTBASE
class AbstractBase
{
public:
virtual ~AbstractBase() = 0;
}
#endif
The child that uses the abstractbase, "child.h":
#ifndef CHILD
#define CHILD
class child : public AbstractBase
{
public:
~child() override;
}
#endif
The implementation in "child.cpp":
#include "child.h"
child::~child()
Obviously there are far more functions, but in essence that's how my real class's destructors look.
After scouring the web for ways of using abstract classes in C++, I am about to give up. As far as I can tell from those sources, this is the way to do it. You declare your abstracts class's destructor virtual, so any call to it will include the child. And the child's destructor is simply marked override. There shouldn't be anything else to it.
Have I missed something truly fundamental here?
PS: added MCVE:
class AbstractBase
{
public:
virtual ~AbstractBase() = 0;
};
class child : public AbstractBase
{
public:
void dostuff()
{
//stuff
}
~child() override
{}
}
int main (argc, char *argv[])
{
child* ptr = new child();
ptr->dostuff();
}
I should add that the errors I now get are not entirely identical, while the original ones look like this:
undefined reference to 'vtable for AbstractBase': In function
AbstractBase:~AbstractBase()': Undefined reference to 'vtable for
AbstractBase': Undefined reference to 'typeinfo for AbstractBase':
Collect2:error:ld returned 1 exit status
You need to define a destructor for every class, otherwise you cannot destroy objects of that class (which includes member objects and base sub-objects):
class AbstractBase
{
public:
virtual ~AbstractBase() = default;
}; // ^^^^^^^^^^^
Some alternative formulations:
User-defined:
struct AbstractBase {
virtual ~AbstractBase() {}
};
Pure-virtual, but defined:
struct AbstractBase {
virtual ~AbstractBase() = 0;
};
AbstractBase::~AbstractBase() = default;
This has the benefit of leaving the class abstract even if you have no other virtual member functions.
Combine the two:
struct AbstractBase {
virtual ~AbstractBase() = 0;
};
AbstractBase::~AbstractBase() {}
I thank you all for your assistance. I eventually stumbled upon a solution.
Apperently, having regular virtual functions in the abstract class causes these issues. I recreated both the fix and the error in my MCVE, observe:
Nonfunctional code:
class AbstractBase
{
public:
virtual void idiot();
virtual ~AbstractBase() = 0;
};
AbstractBase::~AbstractBase()=default;
class child : public AbstractBase
{
public:
void dostuff()
{
//stuff
}
void idiot() override
{
}
~child() override
{
}
};
int main(int argc, char *argv[])
{
child* ptr = new child();
ptr->dostuff();
}
Functional code:
class AbstractBase
{
public:
//virtual void idiot();
virtual ~AbstractBase() = 0;
};
AbstractBase::~AbstractBase()=default;
class child : public AbstractBase
{
public:
void dostuff()
{
//stuff
}
/*void idiot() override
{
}*/
~child() override
{
}
};
int main(int argc, char *argv[])
{
child* ptr = new child();
ptr->dostuff();
}
Notice the only change I made, was commenting out the virtual function idiot, and it's implementation in child.
From my point of view, this is illogical. That extra function should not cause problems.
Alternatively, and this is the true solution, one can make all virtual functions pure. This solves the problem.
I can only guess at what's going on here, it would seem it looks for the implementation of the non-pure functions in a AbstractBase.cpp, which ofcourse doesn't exist. The result is the talk about undefined references to vtables and typeinfo for said AbstractBase, it is right in stating that the virtual functions are indeed undefined. But it shouldn't care, the class is abstract.
My conclusion would be, provided this is intended functionality, that you do need to declare all functions pure if you are to use abstract classes in c++, even though logic dictates it would be unnecessary. At any rate, if it is indeed intended, then the compiler should warn the user. The current errormessages are completely useless.

How to access a non-static method from a thread in C++

//In A.h I have the following code
include "afxwin.h"
include "msclr\auto_gcroot.h"
using namespace System;
using msclr::auto_gcroot;
namespace A
{
public ref class A
{
public:
virtual bool Func();
A();
~A();
virtual bool Connect();
protected:
DWORD WINAPI threadConnect(void* pParam);
};
public class AHelper
{
public:
auto_gcroot A;
};
}
//In A.cpp I have below code
// This is the main DLL file.
include "stdafx.h"
include "A.h"
include "string"
include "sstream"
include "stdlib.h"
include "strsafe.h"
include "windows.h"
include "tchar.h"
namespace A
{
A::A()
{
m_FuncHandle = mpsNil;
}
A::~A()
{
}
bool A::Func()
{
return true;
}
bool A::Connect()
{
AHelper* AHelper;
m_retVal = false;
AHelper = new AHelper();
AHelper->A = this;
HANDLE Handle_Of_Thread = 0;
DWORD dwThreadId;
//DWORD WINAPI threadConnect(void* pParam);
//If I declare the function declaration here I am getting
//error LNK2001: unresolved external symbol "unsigned long __stdcall threadConnect(void *)"
(?threadConnect##YGKPAX#Z)
Handle_Of_Thread = CreateThread
(NULL, 0, threadConnect, AHelper, 0, &dwThreadId); // with this code I am getting
//error C3867: 'A::A::threadConnect': function call missing argument list; use '&A::A::threadConnect' to create a pointer to member
return m_retVal;
}
DWORD WINAPI A::threadConnect(void* pParam)
{
AHelper* AHelper = reinterpret_cast(pParam);
//Here I need to call Func
return 0;
}
}
the usual trick is to have a static function that takes an id of some sort, this function determines which someFunc() to call (as each object will have its own someFunc, you obviously need to know which one) either using a lookup, or as is common in C/C++ apps, by passing the address of the object directly.
so you have something like:
static bool thread_func(object o)
{
return o->someFunc();
}
The trick is that the static function must be reentrant, so holds no state itself for the threads to interfere with (or if it does, make sure its thread safe)
That all supposes you're calling a method on an object that was not created within the thread. If you're just calling a function and you already have the object created within your thread, just call the function!

Passing non static delegate property function as parameter in C++ / CLI

I make a interface class in C++ for voice recognition, i´m using the Julius API. http://julius.sourceforge.jp/en_index.php?q=index-en.html.
Well, my class has some events, these events will be triggered by the Julius API.
The Julius API has the function call callback_add with this signature:
int callback_add (Recog *recog, int code, void(*func)(Recog *recog, void *data), void data)
I using some 'proxy' functions to Invoke the events and passing this functions to callback_add.
If the property event is static, it works fine, but if is a non static, inside the proxy function the property not be recognized.
The difficult is because I have to use the callback_add function and can't modify this.
Here is a summary of the class with 2 events (static and non-static)
Header
#ifndef FALAENGINE_H_
#define FALAENGINE_H_
#pragma once
extern "C"{
#include <julius/julius.h>
}
namespace FalaAPI {
public ref class FalaEngine
{
public:
FalaEngine();
~FalaEngine();
// Events
delegate void OnRecognizedDele(FalaAPI::RecoResult^ result);
static property OnRecognizedDele^ OnRecognized;
delegate void OnEngineStartDele();
property OnEngineStartDele^ OnEngineStart;
private:
Recog *recog;
Jconf *jconf;
};
}
#endif /* FALAENGINE_H_*/
Source
#include "stdafx.h"
using System::String;
using System::Console;
#include "FalaEngine.h"
#include <windows.h>
namespace FalaAPI{
void StartOnEngineStart()(Recog *recog, void * dummy){
if(FalaEngine::OnEngineStart->GetInvocationList()->Length > 0)
FalaEngine::OnEngineStart->Invoke();
}
void StartOnRecognized()(Recog *recog, void * dummy){
if(FalaEngine::OnRecognized->GetInvocationList()->Length > 0)
FalaEngine::OnRecognized->Invoke();
}
FalaEngine::FalaEngine(){
recog = j_recog_new();
jconf = j_jconf_new();
//Julius callback Functions
callback_add(recog, CALLBACK_EVENT_PROCESS_ONLINE, StartOnEngineStart, NULL);
callback_add(recog, CALLBACK_RESULT, StartOnRecognized, NULL);
}
}
The problem occurs inside StartOnEngineStart function:
error C2227: left of '->GetInvocationList' must point to class/struct/union/generic type
A non-static member exists separately in each instance. You haven't specified which instance contains the delegate you want to inspect, you've only specified a class (and there may be many instances).
Try using the dummy parameter to pass your instance. But be careful, because the garbage collector will move objects around unless you have pinned them, so simply passing the address will not work. You need to create and pass a GCHandle instead. (Be careful not to leak the GCHandle, or your object will never be released)
Something like this should be effective:
ref class FalaEngine;
struct EngineHandle
{
gcroot<FalaEngine^> handle;
EngineHandle(FalaEngine^ engine) : handle(engine) {}
};
public ref class FalaEngine
{
clr_scoped_ptr<EngineHandle> callback_ptr;
public:
FalaEngine();
~FalaEngine();
// Events
delegate void OnRecognizedDele(FalaAPI::RecoResult^ result);
property OnRecognizedDele^ OnRecognized;
delegate void OnEngineStartDele();
property OnEngineStartDele^ OnEngineStart;
private:
Recog *recog;
Jconf *jconf;
};
void StartOnEngineStart(Recog *recog, void * dummy)
{
FalaEngine^ that = static_cast<EngineHandle*>(dummy)->handle;
that->OnEngineStart(); // C++/CLI already checks if the invocation list is empty
}
void StartOnRecognized(Recog *recog, void * dummy)
{
FalaEngine^ that = static_cast<EngineHandle*>(dummy)->handle;
that->OnRecognized(recog->get_result());
}
FalaEngine::FalaEngine()
: callback_ptr(new EngineHandle(this))
{
recog = j_recog_new();
jconf = j_jconf_new();
//Julius callback Functions
callback_add(recog, CALLBACK_EVENT_PROCESS_ONLINE, StartOnEngineStart, callback_ptr.get());
callback_add(recog, CALLBACK_RESULT, StartOnRecognized, callback_ptr.get());
}
The clr_scoped_ptr class is here. There are not many license requirements, make sure you follow them though if you use it.

Resources