62

I have a C library that needs a callback function to be registered to customize some processing. Type of the callback function is int a(int *, int *).

I am writing C++ code similar to the following and try to register a C++ class function as the callback function:

class A {
  public:
   A();
   ~A();
   int e(int *k, int *j);
};

A::A()
{
   register_with_library(e)
}

int
A::e(int *k, int *e)
{
  return 0;
}

A::~A() 
{

}

The compiler throws following error:

In constructor 'A::A()',
error:
 argument of type ‘int (A::)(int*, int*)’ does not match ‘int (*)(int*, int*)’.

My questions:

  1. First of all is it possible to register a C++ class member function like I am trying to do and if so how? (I read 32.8 at http://www.parashift.com/c++-faq-lite/mixing-c-and-cpp.html. But in my opinion it does not solve the problem)
  2. Is there a alternate/better way to tackle this?
Steve Friedl
  • 3,929
  • 1
  • 23
  • 30
Methos
  • 13,608
  • 11
  • 46
  • 49

8 Answers8

51

You can do that if the member function is static.

Non-static member functions of class A have an implicit first parameter of type class A* which corresponds to this pointer. That's why you could only register them if the signature of the callback also had the first parameter of class A* type.

sharptooth
  • 167,383
  • 100
  • 513
  • 979
  • yes. that solution worked. What confuses me is compiler did not show error int (A::)(A *, int*, int*)’ does not match ‘int ()(int, int*)’ – Methos Jun 16 '09 at 10:31
  • 1
    It did, but by putting (A::) which means that function is part of class A, which from there implies the 'this' pointer. – GManNickG Jun 16 '09 at 10:37
  • I'm just curious... is this specified in the standard? I just glanced at the section on classes and didn't find this. Nevertheless, very interesting. I just wouldn't think that every compiler necessarily has to handle non-static member functions in this way. – Tom Jun 16 '09 at 10:59
  • @Methos, saying that member functions have an implicit first parameter doesn't mean that parameter really exist. It means that conceptually, it's there. – Johannes Schaub - litb Jun 16 '09 at 11:00
  • 2
    @Tom, the standard calls it "implicit object parameter", and it's of type A& for non-const member functions, and A const& for const member functions, A volatile& for volatile... and so on. It's a reference, while "this" is a pointer - mostly because of history. The object that the member function is called on is called "implied object argument". The implicit object parameter is treated as a hidden first parameter for purpose of overload resolution - but this all is only conceptual, nothing that really has to be there – Johannes Schaub - litb Jun 16 '09 at 11:02
  • "That's why you could only register them if the signature of the callback also had the first parameter of class A* type" --- doing so would be undefined behaviour and would not work for all kinds of member functions. – n. m. could be an AI Dec 18 '16 at 06:35
40

You can also do this if the member function is not static, but it requires a bit more work (see also Convert C++ function pointer to c function pointer):

#include <stdio.h>
#include <functional>

template <typename T>
struct Callback;

template <typename Ret, typename... Params>
struct Callback<Ret(Params...)> {
   template <typename... Args> 
   static Ret callback(Args... args) {                    
      return func(args...);  
   }
   static std::function<Ret(Params...)> func; 
};

template <typename Ret, typename... Params>
std::function<Ret(Params...)> Callback<Ret(Params...)>::func;

void register_with_library(int (*func)(int *k, int *e)) {
   int x = 0, y = 1;
   int o = func(&x, &y);
   printf("Value: %i\n", o);
}

class A {
   public:
      A();
      ~A();
      int e(int *k, int *j);
};

typedef int (*callback_t)(int*,int*);

A::A() {
   Callback<int(int*,int*)>::func = std::bind(&A::e, this, std::placeholders::_1, std::placeholders::_2);
   callback_t func = static_cast<callback_t>(Callback<int(int*,int*)>::callback);      
   register_with_library(func);      
}

int A::e(int *k, int *j) {
   return *k - *j;
}

A::~A() { }

int main() {
   A a;
}

This example is complete in the sense that it compiles:

g++ test.cpp -std=c++11 -o test

You will need the c++11 flag. In the code you see that register_with_library(func) is called, where func is a static function dynamically bound to the member function e.

Anne van Rossum
  • 3,091
  • 1
  • 35
  • 39
  • Cool! I've always wanted to know how to do this. – Jacko Nov 01 '15 at 14:58
  • What if the C callback has is of the form int __stdcall callback(int*, int*) ? – Jacko Nov 01 '15 at 15:53
  • 1
    @Jacko. Mmm... that's about callee/caller responsible for stack cleanup isn't it? I don't know... I forgot everything about Windows. :-) – Anne van Rossum Nov 01 '15 at 18:55
  • @Jacko: static Ret __stdcall callback(Arg arg) – Martin.Martinsson Aug 14 '16 at 17:15
  • 1
    How would one do this to be threadsafe? I've posted the question here: http://stackoverflow.com/questions/41198854/using-a-c-class-member-function-as-a-c-callback-function-thread-safe-version – Victor.dMdB Dec 17 '16 at 13:57
  • 1
    Your answer is highly appreciated! – Dimfred Apr 13 '19 at 17:25
  • Should be `return func(args...);` instead of `func(args...);` in line 11 – sorush-r Oct 17 '19 at 14:00
  • @sorush-r Or...? What failure did you encounter? – Anne van Rossum Oct 18 '19 at 08:49
  • @AnnevanRossum A compile error complaining about not returning a value from a non-void function. – sorush-r Oct 18 '19 at 08:58
  • Ah, I haven't seen that (just checked again with gcc). It doesn't hurt though. :-) I'll adjust the post. – Anne van Rossum Oct 18 '19 at 08:59
  • 2
    @AnnevanRossum your solution is great, but I ran into an issue of trying to create two such callbacks and the second overriding the first. I posted at https://stackoverflow.com/q/66474621/2725742 about what the minimal change necessary would be to have to separate "static wrappers" like this. – user2725742 Mar 04 '21 at 12:46
  • @user2725742 Your solution of adding an extra template parameter is then indeed the minimal change I'd recommend. – Anne van Rossum Mar 05 '21 at 13:07
  • Hello, your solution is very useful. I am wondering if it is possible to generalize this solution for several instances of a class? Currently, the second instance overwrite the binding of the first instance due to static member. I have no idea to do that, it is a too advance code programming for me. – avasygn Jun 07 '22 at 16:55
6

The problem is that method != function. The compiler will transform your method to something like that:

int e( A *this, int *k, int *j );

So, it's sure you can't pass it, because the class instance can't be passed as argument. One way to work around is to make the method as static, this way it would have the good type. But it won't any class instance, and access to non-static class members.

The other way is to declare a function with a static Pointer to a A initialised the first time. The function only redirect the call to the class :

int callback( int *j, int *k )
{
    static A  *obj = new A();
    a->(j, k);
}

Then you can register the callback function.

Rapptz
  • 20,807
  • 5
  • 72
  • 86
Raoul Supercopter
  • 5,076
  • 1
  • 34
  • 37
  • What's a 'method' in C++? That word doesn't ever appear one single time in C++ standard. – Aconcagua Apr 13 '19 at 12:38
  • @Aconcagua, I would imagine you know, but here is an answer to your question: https://stackoverflow.com/questions/8596461/in-c-what-is-the-difference-between-a-method-and-a-function#answer-8596481 – Alexis Wilke Apr 30 '19 at 18:07
  • A function member ("method") is definitely a function. The fact that there is (indeed) an additional parameter does not make it a non-function object. – Alexis Wilke Apr 30 '19 at 18:09
  • @AlexisWilke Much more important are the first two ***comments*** to the referred answer. Additionally second paragraph ("interchangability") would imply "function != function". It might look like splitting hairs at a first glance, but I had to learn it the hard way (slight misunderstandings leading to heavy bugs) how important clear definitions are. So deducing two important rules: 1. Don't use terminology that isn't clearly defined! 2. Don't use new definitions in parallel to existing ones. – Aconcagua May 01 '19 at 06:37
  • In given case, even both rules are violated, as there's already 'member function' and 'method isn't even clearly defined in C++. Not software now, but still an [example](https://en.wikipedia.org/wiki/Tenerife_airport_disaster#Communication_misunderstandings) what might happen if terminology is not clear (enough). Side note: terminology was standardised afterwards with clearly distinguishable wording... – Aconcagua May 01 '19 at 06:39
  • 1
    In `a->(j, k);`, did you miss typing the `e`? – Alexis Wilke May 02 '19 at 03:55
5

Well ...if you are on a win32 platform there is always the nasty Thunking way ...

Thunking in Win32: Simplifying callbacks to non-static member functions

It is a solution but I don't recommend using it.
It has a good explanation and it is nice to know it exists.

TimW
  • 8,351
  • 1
  • 29
  • 33
1

In this solution, we have a template class with the static method to be given to the "c function" as a callback. This class holds a "ordinary" object ( with a member function named callback() which will be finally called).

Once your class (here, A) is defined, it can be easily used:

int main() {

  Holder<A> o ( A(23, 23) );

  std::cout << o().getN() << "\n";

  callACFunctionPtr( fun );

  callACFunctionPtr( o.callback );

} // ()

Complete example:

#include <iostream>

// ----------------------------------------------------------
// library class: Holder
// ----------------------------------------------------------
template< typename HeldObjectType >
class Holder {
public:
  static inline HeldObjectType object;

  static void callback( ) {
    object.callback();
  } // ()

  HeldObjectType &  operator() ( ) {
    return object;
  }

  Holder( HeldObjectType && obj )
  {
    object = obj;
  }

  Holder() = delete;

}; // class

// ----------------------------------------------------------
// "old" C function receivin a ptr to function as a callback
// ----------------------------------------------------------
using Callback = void (*) (void);

// ..........................................................
// ..........................................................
void callACFunctionPtr( Callback f ) {
  f();
} // ()

// ----------------------------------------------------------
// ----------------------------------------------------------
void fun() {
  std::cout << "I'm fun\n";
} // 

// ----------------------------------------------------------
// 
// Common class where we want to write the
// callback to be called from callACFunctionPtr.
// Name this function: callback
// 
// ----------------------------------------------------------
class A {
private:
  int n;

public:

  A(  ) : n( 0 ) { }

  A( int a, int b ) : n( a+b ) { }

  void callback( ) {
    std::cout << "A's callback(): " << n << "\n";
  }

  int getN() {
    return n;
  }

}; // class

// ----------------------------------------------------------
// ----------------------------------------------------------
int main() {

  Holder<A> o ( A(23, 23) );

  std::cout << o().getN() << "\n";

  callACFunctionPtr( fun );

  callACFunctionPtr( o.callback );

} // ()
cibercitizen1
  • 20,944
  • 16
  • 72
  • 95
0

The problem with using a member function is that it needs an object on which to act - and C doesnt know about objects.

The easiest way would be to do the following:

//In a header file:
extern "C" int e(int * k, int * e);

//In your implementation: 
int e(int * k, int * e) { return 0; }
pauljwilliams
  • 19,079
  • 3
  • 51
  • 79
0

To anyone coming accross that issue in 2022, I will offer a new approach that is compliant with the initial request. I will welcome any feedback about this solution, and hope this can help anyone coming accross that topic.

First we need to understand that the core issue -as some highlighted already- is that a non-static method (which can access object's members etc..) need to access 'this', the object's instance pointer. However since we want our function to be a callback, we cannot modify the way it will be called. This is why we need to have a function that can access its object's 'this' pointer.

My solution is to modify a dummy function clone's code at runtime and pass its address as the callback function, which then once called will be able to resolve its assigned object pointer. This dummy is templated in a wrapper, so it can adapt to any desired signature.

First here are my repos links in case the code is updated in future (https://github.com/Ezarkei/BindFunctorToC https://gitlab.com/Ezarkei/BindFunctorToC)

So here is how to use it:

    Object instance{}; //Create an instance
    BindFunctorToC<Object> binder{instance}; //Create a binder on that instance
    void(*fPtr)(void){binder()}; //Get the C-style function pointer from the binder, here the signature is void(*)(void)
    fPtr(); //Call the C-style function pointer

Then a more detailed example:

#include "BindFunctorToC.hpp"

#include <iostream>

struct Foo {
    int operator()(std::string const &other) const noexcept { //This is our functor, the "entry point" to our object from the C-style function pointer call
    return Bar(other); //Here this functor simply forwards to a method
    }
    int Bar(std::string const &other) const noexcept { //This method is non-static and will use an object's member: _str
    std::cout << _str << ' ' << other << std::endl; //Beeing able to access _str here clearly shows that it's not a trick, we have a direct access to 'this'
    return 0;
    }
    std::string const _str{"default"};
};

static void CallBack(int(*callback)(std::string const &)) noexcept { //This is the kind of use case we want to be able to accomplish, a simple C-style function pointer is passed as parameter but it will effectively call a non-static method on an object
    callback("world"); //Here we will call foo1 instance's operator(), hence foo1's 'Bar' method
}

int main(void) {
    Foo foo1{"hello"}, foo2{"foo"}; //First we declare 2 instances of Foo, with 2 different member values so we can distinguish them well
    BindFunctorToC<Foo> binder1{foo1}, binder2{foo2}; //For every instance a binder is needed
    int(*ptr)(std::string const &){binder1()}; //We then construct a C-style function pointer with Foo's operator() signature and initialize it to binder1 function by calling binder1's operator()
    CallBack(ptr); //Here we will pass our C-style function pointer to the C api which may need it as a callback
    return binder2()("bar"); //Proof that we work on instances, first the operator() will get the C-style function pointer, then we call it and return its value to show the signatures deduction works
}

And finally the binder code available on the repos (content of BindFunctorToC.hpp):

//******************************************************************************
//* Copyright (c) 2022 Ezarkei                                                 *
//*                                                                            *
//* This document is under the MIT License                                     *
//******************************************************************************

#ifndef BINDFUNCTORTOC_HPP_
#define BINDFUNCTORTOC_HPP_

#if ((defined(__i386__) || defined(__x86_64__) || defined(__arm__)) && (defined(__linux__) || defined(__linux) || defined(linux) || defined(__unix__) || defined(__unix))) || (defined(WIN32) || defined(_WIN32) || defined(__WIN32__))

#if defined(WIN32) || defined(_WIN32) || defined(__WIN32__)
#if defined(_DEBUG) || defined(DEBUG)
#error Requires release compilation (windows)
#endif
#define __win32__
#endif

#ifdef __win32__
#define __attribute__(__)
#include <windows.h>
#else
#include <sys/mman.h>
#include <unistd.h>
#include <cstring>
#endif

#include <type_traits>
#include <stdexcept>
#include <string>

#ifdef __win32__
#define __DCL__(_) ((typename decltype(_))(_))
#else
#define __DCL__(_) (_)
#endif
#define __FLG__ 0x21626e636967616d

template<typename R> struct __TTRf__ {
    explicit __TTRf__(void) noexcept = delete;
    using _R = R &;
};

template<typename> struct __BndFcntrTC__;
template<typename R, typename T, typename ...A> struct __BndFcntrTC__<R(T::*)(A...)> {
public:
    explicit __BndFcntrTC__(T &);
    ~__BndFcntrTC__(void) noexcept;

    R(*operator()(void) const noexcept)(A...);

    R(&_mppr)(__BndFcntrTC__<R(T::*)(A...)> &, typename __TTRf__<A>::_R...) noexcept = &__MdmMppr__<>;

private:
    void __MplcDdrss__(void const *const);

    template<typename O = R> static typename std::enable_if<std::is_same<O, void>::value, void>::type __MdmMppr__(__BndFcntrTC__<R(T::*)(A...)> &, typename __TTRf__<A>::_R...) noexcept;
    template<typename O = R> static typename std::enable_if<!std::is_same<O, void>::value, O>::type __MdmMppr__(__BndFcntrTC__<R(T::*)(A...)> &, typename __TTRf__<A>::_R...) noexcept;
    static std::size_t __PgSzClcltr__(void) noexcept;
    static std::size_t __RwTmpltSzClcltr__(void) noexcept;

    static std::size_t const _flg, _pgSz, _rwTmpltSz, _sgmntSz;
    T &_trgt;
    void *_sgmnt;
};

template<typename> struct __CnstNxcptBstrct__;
template<typename R, typename T, typename ...A> struct __CnstNxcptBstrct__<R(T::*)(A...)> {
    explicit __CnstNxcptBstrct__(void) noexcept = delete;
    using _S = R(T::*)(A...);
};

template<typename R, typename T, typename ...A> struct __CnstNxcptBstrct__<R(T::*)(A...) const> {
    explicit __CnstNxcptBstrct__(void) noexcept = delete;
    using _S = typename __CnstNxcptBstrct__<R(T::*)(A...)>::_S;
};

#if __cplusplus > 201402L

template<typename R, typename T, typename ...A> struct __CnstNxcptBstrct__<R(T::*)(A...) noexcept> {
    explicit __CnstNxcptBstrct__(void) noexcept = delete;
    using _S = typename __CnstNxcptBstrct__<R(T::*)(A...)>::_S;
};

template<typename R, typename T, typename ...A> struct __CnstNxcptBstrct__<R(T::*)(A...) const noexcept> {
    explicit __CnstNxcptBstrct__(void) noexcept = delete;
    using _S = typename __CnstNxcptBstrct__<R(T::*)(A...)>::_S;
};

#endif

template<typename T> class BindFunctorToC : public __BndFcntrTC__<typename __CnstNxcptBstrct__<decltype(&T::operator())>::_S> {
public:
    explicit BindFunctorToC(T &);
};

template<typename R, typename T, typename ...A> __attribute__((noinline, unused)) void __SzClcltrE__(void) noexcept;
template<typename R, typename T, typename ...A> __attribute__((noinline, optimize(3))) typename std::enable_if<std::is_same<R, void>::value, void>::type __RwTmplt__(A...) noexcept;
template<typename R, typename T, typename ...A> __attribute__((noinline, optimize(3))) typename std::enable_if<!std::is_same<R, void>::value, R>::type __RwTmplt__(A...) noexcept;

template<typename R, typename T, typename ...A> __BndFcntrTC__<R(T::*)(A...)>::__BndFcntrTC__(T &trgt) : _trgt{trgt} {
#ifdef __win32__
    (void const *const)(_rwTmpltSz + _pgSz);
    _sgmnt = VirtualAlloc(NULL, _sgmntSz, MEM_COMMIT, PAGE_READWRITE);
    if (!_sgmnt)
        throw std::runtime_error{std::string{"VirtualAlloc error :: "} + std::to_string(GetLastError())};
#else
    _sgmnt = mmap(nullptr, _sgmntSz, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
    if (MAP_FAILED == _sgmnt)
        throw std::runtime_error{std::string{"Mmap error :: "} + strerror(errno)};
#endif
    void const *const sgmnt{(void const *)__DCL__((&__RwTmplt__<R, T, A...>))};
    std::memcpy(_sgmnt, sgmnt, _rwTmpltSz);
    __MplcDdrss__(this);
#ifdef __win32__
    unsigned long dscrd;
    if (!VirtualProtect(_sgmnt, _sgmntSz, PAGE_EXECUTE_READ, &dscrd))
        throw std::runtime_error{std::string{"VirtualProtect error :: "} + std::to_string(GetLastError())};
#else
    if (mprotect(_sgmnt, _sgmntSz, PROT_EXEC | PROT_READ))
        throw std::runtime_error{std::string{"Mprotect error :: "} + strerror(errno)};
    __builtin___clear_cache(_sgmnt, (uint8_t*)_sgmnt + _rwTmpltSz);
#endif
}

template<typename R, typename T, typename ...A> __BndFcntrTC__<R(T::*)(A...)>::~__BndFcntrTC__(void) noexcept {
#ifdef __win32__
    if (!VirtualFree(_sgmnt, 0, MEM_RELEASE))
#else
    if (munmap(_sgmnt, _sgmntSz))
#endif
        abort();
}

template<typename R, typename T, typename ...A> R(*__BndFcntrTC__<R(T::*)(A...)>::operator()(void) const noexcept)(A...) {
    return (R(*)(A...))_sgmnt;
}

template<typename R, typename T, typename ...A> void __BndFcntrTC__<R(T::*)(A...)>::__MplcDdrss__(void const *const ddrss) {
    std::size_t const tht{(std::size_t const)ddrss};
    uint8_t *ffst{nullptr}, m{0};
    for (std::size_t i{0}, j{0}, k{0}; !ffst && _rwTmpltSz > i; ++i)
        if (j[(uint8_t*)&_flg] == i[(uint8_t*)_sgmnt]) {
            if (!j++)
                k = i;
            else if (sizeof(void *volatile const) <= j)
                ffst = (uint8_t*)_sgmnt + k;
        } else if (j)
            j = 0;
    if (ffst)
        std::memcpy(ffst, &tht, sizeof(void *volatile const));
    else {
        for (std::size_t i{0}; !ffst && _rwTmpltSz > i; ++i)
            for (uint8_t l{0}; !ffst && 8 > l; l += 4)
                for (std::size_t j{0}, k{0}; _rwTmpltSz > i + j + k && 7 > j; 2 == j ? (j += 2, k = l) : ++j)
                    if (!(j % 4 ? j % 2 ? (uint8_t{(uint8_t)(j[(uint8_t *)_sgmnt + i + k] << 4)} >> 4) == uint8_t{(uint8_t)((j / 4 ? 3 : 1)[(uint8_t *)&_flg] << 4)} >> 4 : (uint8_t{(uint8_t)(j[(uint8_t *)_sgmnt + i + k] << 4)} >> 4) == (j / 4 ? 3 : 1)[(uint8_t *)&_flg] >> 4 : j[(uint8_t *)_sgmnt + i + k] == (j / 2)[(uint8_t *)&_flg]))
                        j = 7;
                    else if (6 == j) {
                        ffst = (uint8_t *)_sgmnt + i;
                        m = l;
                    }
        if (ffst)
            for (std::size_t i{0}, k{0}; 7 > i; 2 == i ? (i += 2, k = m) : ++i)
                i % 4 ? ((i[ffst + k] >>= 4) <<= 4) |= i % 2 ? uint8_t{(uint8_t)((i / 4 ? 3 : 1)[(uint8_t *)&tht] << 4)} >> 4 : (i / 4 ? 3 : 1)[(uint8_t *)&tht] >> 4 : i[ffst + k] = (i / 2)[(uint8_t *)&tht];
    }
    if (!ffst)
        throw std::runtime_error{"Failed to resolve flag offset"};
}

template<typename R, typename T, typename ...A> template<typename O> typename std::enable_if<std::is_same<O, void>::value, void>::type __BndFcntrTC__<R(T::*)(A...)>::__MdmMppr__(__BndFcntrTC__<R(T::*)(A...)> &tht, typename __TTRf__<A>::_R... __flds__) noexcept {
    tht._trgt.operator()(std::forward<A>(__flds__)...);
}

template<typename R, typename T, typename ...A> template<typename O> typename std::enable_if<!std::is_same<O, void>::value, O>::type __BndFcntrTC__<R(T::*)(A...)>::__MdmMppr__(__BndFcntrTC__<R(T::*)(A...)> &tht, typename __TTRf__<A>::_R... __flds__) noexcept {
    return tht._trgt.operator()(std::forward<A>(__flds__)...);
}

template<typename R, typename T, typename ...A> void __SzClcltrE__(void) noexcept {
    __SzClcltrE__<R, T, A...>();
}

template<typename R, typename T, typename ...A> typename std::enable_if<std::is_same<R, void>::value, void>::type __RwTmplt__(A... __flds__) noexcept {
    void *volatile const __RwTmpltRmPtr__{(void *)__FLG__};
    __BndFcntrTC__<R(T::*)(A...)> &tht{*((__BndFcntrTC__<R(T::*)(A...)> *const)__RwTmpltRmPtr__)};
    tht._mppr(tht, __flds__...);
}

template<typename R, typename T, typename ...A> typename std::enable_if<!std::is_same<R, void>::value, R>::type __RwTmplt__(A... __flds__) noexcept {
    void *volatile const __RwTmpltRmPtr__{(void *)__FLG__};
    __BndFcntrTC__<R(T::*)(A...)> &tht{*((__BndFcntrTC__<R(T::*)(A...)> *const)__RwTmpltRmPtr__)};
    return tht._mppr(tht, __flds__...);
}

template<typename R, typename T, typename ...A> std::size_t __BndFcntrTC__<R(T::*)(A...)>::__PgSzClcltr__(void) noexcept {
#ifdef __win32__
    SYSTEM_INFO nf{};
    GetSystemInfo(&nf);
    return nf.dwPageSize;
#else
    return (std::size_t)sysconf(_SC_PAGESIZE);
#endif
}

template<typename R, typename T, typename ...A> std::size_t __BndFcntrTC__<R(T::*)(A...)>::__RwTmpltSzClcltr__(void) noexcept {
    if ((std::size_t)__DCL__((&__RwTmplt__<R, T, A...>)) > (std::size_t)&__SzClcltrE__<R, T, A...>)
        abort();
    return (std::size_t)&__SzClcltrE__<R, T, A...> - (std::size_t)__DCL__((&__RwTmplt__<R, T, A...>));
}

template<typename R, typename T, typename ...A> std::size_t const __BndFcntrTC__<R(T::*)(A...)>::_flg{(std::size_t)__FLG__};

template<typename R, typename T, typename ...A> std::size_t const __BndFcntrTC__<R(T::*)(A...)>::_pgSz{__PgSzClcltr__()};

template<typename R, typename T, typename ...A> std::size_t const __BndFcntrTC__<R(T::*)(A...)>::_rwTmpltSz{__RwTmpltSzClcltr__()};

template<typename R, typename T, typename ...A> std::size_t const __BndFcntrTC__<R(T::*)(A...)>::_sgmntSz{(_rwTmpltSz / _pgSz + 1) * _pgSz};

template<typename T> BindFunctorToC<T>::BindFunctorToC(T &trgt) : __BndFcntrTC__<typename __CnstNxcptBstrct__<decltype(&T::operator())>::_S>(trgt) {
}

#ifdef __win32__
#undef __win32__
#undef __attribute__
#endif
#undef __DCL__
#undef __FLG__

#else
#error Unknown system ; supports unix(-like) (x86_64, i386, arm) and windows (x64, x32)
#endif
#endif
Ezarkei
  • 1
  • 3
0

This old answer still applies: FLTK callbacks won't accept my function pointers The details might be a bit different. But it works.

Red.Wave
  • 2,790
  • 11
  • 17