Passing function pointer to Cxx

I am using the Cxx.jl to wrap a C++ library. Now the C++ library has some methods that take function pointers as arguments. Is there a recommended way to wrap such a function? As a minimal example say I want to wrap

using Cxx
cxx"""
void evaluate(void (*f)() ){
    f();
}
"""

I could pass a julia function by doing

function evaluate(f_jl)
    cxx"void f_xx(){$f_jl();}"
    icxx"evaluate(&f_xx);"
end
f() = println("heyho")
evaluate(f)
heyho

However this does not allow to pass another function later on:

g() = println("heyho")
evaluate(g)

LoadError: Clang did not create a global variable for the given VarDecl
while loading In[3], in expression starting on line 3

 in SetDeclInitializer(::Cxx.ClangCompiler, ::Cxx.CppPtr{Cxx.CxxQualType{Cxx.CppBaseType{Symbol("clang::VarDecl")},(false,false,false)},(false,false,false)}, ::Cxx.CppPtr{Cxx.CxxQualType{Cxx.CppBaseType{Symbol("llvm::Constant")},(false,false,false)},(false,false,false)}) at /home/admin/.julia/v0.5/Cxx/src/cxxstr.jl:35
 in ArgCleanup(::Cxx.ClangCompiler, ::Function, ::Cxx.CppPtr{Cxx.CxxQualType{Cxx.CppBaseType{Symbol("clang::VarDecl")},(false,false,false)},(false,false,false)}) at /home/admin/.julia/v0.5/Cxx/src/cxxstr.jl:191
 in macro expansion at /home/admin/.julia/v0.5/Cxx/src/cxxstr.jl:661 [inlined]
 in evaluate(::Function) at ./In[1]:11


I found a way that seems to work, however I am still not sure if this is a sane solution?

function evaluate(f)
    f_void_ptr = cfunction(f, Void, ()) # void pointer on f. Need to cast it to function pointer
    icxx"""
    typedef void (*fptr)();
    fptr f_fun_ptr = reinterpret_cast<fptr>(reinterpret_cast<long>($f_void_ptr));
    evaluate(f_fun_ptr);
    """
end
f() = println("hi")
evaluate(f)
hi
g() = println("ho")
evaluate(g)
ho

cfunction should be the way to go, yes, but I don’t understand why you need to cast to long first?

1 Like

Thanks! I guess the long cast is not necessary.

It’s not only not necessary, it’s actively harmful: it will break e.g. on 64-bit Windows, where long if 4 bytes while pointers are 8 bytes.

1 Like

For anyone that is interested doing this

using Cxx

cxx"""
void evaluatec(void (*f)() ){
    f();
}
"""

function evaluate(f)
    f_void_ptr = @cfunction($f, Cvoid, ()) # void pointer on f. Need to cast it to function pointer
    f_void_ptr2 = f_void_ptr.ptr
    #show(typeof(f_void_ptr))
    icxx"""
    typedef void (*fptr)();
    fptr f_fun_ptr = reinterpret_cast<fptr>($f_void_ptr2);
    evaluatec(f_fun_ptr);
    """
end


f() = println("hi")
evaluate(f)



g() = print("ho")
evaluate(g)

works under 1.0.2

Cxx.jl works under julia 1.0.2? Cool :partying_face:

Yes, if you complie julia from source :laughing: