C++ 如何使用可变参数注册回调并传递值

C++ 如何使用可变参数注册回调并传递值,c++,variadic,C++,Variadic,你能帮我做一下吗。 我在第三个lib头中有回调函数定义: #ifdef __cplusplus extern "C" { #endif typedef int (*SOCK_CLBK)(int, short, unsigned char*, int, ...); #ifdef __cplusplus } #endif #include "CSocket.h" #ifndef WIN32 #include <pthread.h> #else

你能帮我做一下吗。 我在第三个lib头中有回调函数定义:

#ifdef __cplusplus
extern "C" {
#endif
typedef int (*SOCK_CLBK)(int, short, unsigned char*, int, ...);
#ifdef __cplusplus
}
#endif
#include "CSocket.h"

#ifndef WIN32
#include <pthread.h>
#else
#include <windows.h>
#include <WinSock.h>
#endif

#define CPP_TCP_MAX_CLIENTS 17
#define CPP_TCP_MAX_SIZE 1500 //In accordance with MTU definitoins

class DLLCPP_API CSERVER {
public:
    /**
     * default constructor
     */
    CSERVER ();
    /**
     * default destructor
     */
    virtual ~CSERVER ();

    /**! \fn int Create(unsigned int uiPort, bool bClbk);
    *   \brief creates singleton socket listener
    *   creates singleton socket listener, which is invoked within dedicated thread
    *   if bClbk is true, otherwise within the main thread.
    *   \param uiPort socket listener port
    *   \param fnClbk call-back function address. if not NULL then callback mode of operation. otherwise normal.
    *   \return 0 on success, error id otherwise.
    */
    int registerCallback(unsigned int uiPort, SOCK_CLBK fnClbk=NULL, int iMsgMaxSize=512)throw (CMException);
….
…
Send()…
….
...

protected:
#ifndef WIN32
    friend void* _fnTCPClbkThread(void *);  //call-back argument for pthread_create within RunClbkThread.
#else
    friend DWORD WINAPI _fnTCPClbkThread( LPVOID lpParam );
#endif

    /**! \fn int IsPending(int iSock, bool& bFail)
     * \brief check pending connection on a non blocking socket
     *  actuall checks for errors and whether or not connection is ready for write operation.
     * \param iSock client socket connection to check.
     * \return: OK (0) if iSock ready for write operation or ERROR otherwise (still pending for instance)
     */
    int IsPending(int iSock)throw (CMException);
    int RunClbkThread();
    int CreateClbk()throw (CMException);
    void ClbkThread();
private:
    typedef void (CSERVER::*PCLBKTHREAD)(void *);
    PCLBKTHREAD _pThreadClbk;
    int     _iServerSock;
    int     _iSock;         
    SOCK_CLBK   _fnClbk;
    unsigned int _uiPort;
    int _iAddrLen;
    bool _bClbkThreadAlive;
    int _iClientConnectionsArr[CPP_TCP_MAX_CLIENTS];
    int _iMsgMaxSize;
    struct sockaddr_in  _saddConnect ;
#ifdef WIN32
    WSADATA m_wsaData;
    HANDLE  _thread;
#else
    pthread_t _thread;
#endif

};
我用以下方式定义回调:

头文件:

template<typename T>
    int ReadTCP(int socket, short code, unsigned char* msg, int received, T a);
模板
int ReadTCP(int套接字,短代码,无符号字符*msg,int接收,ta);
cpp文件:

template<>
    int ReadTCP(int socket, short code, unsigned char* msg, int received, int a)
    {
        return 0;
    }
模板
int ReadTCP(int套接字,短代码,无符号字符*msg,int接收,int a)
{
返回0;
}
并在代码中注册我的回调:

server->registerCallback(port, (SOCK_CLBK)(ReadTCP<int>),maxTCPsize);
server->registerCallback(端口,(SOCK_CLBK)(ReadTCP),maxTCPsize);
这工作正常,并且在需要时触发回调

问题是,“inta”每次都包含随机值。 如何注册回调并传递我自己的特定值(例如100000),这将发生在“a”中的回调中

差不多

server->registerCallback(port, (SOCK_CLBK)(&std::bind(ReadTCP<int>,_1,_2,_3,_4, 100000),maxTCPsize);
server->registerCallback(端口,(SOCK\u CLBK)(&std::bind(ReadTCP,_1,_2,_3,_4,100000),maxTCPsize);
但这不起作用(触发运行时异常)

我做错了什么

库标题:

#ifdef __cplusplus
extern "C" {
#endif
typedef int (*SOCK_CLBK)(int, short, unsigned char*, int, ...);
#ifdef __cplusplus
}
#endif
#include "CSocket.h"

#ifndef WIN32
#include <pthread.h>
#else
#include <windows.h>
#include <WinSock.h>
#endif

#define CPP_TCP_MAX_CLIENTS 17
#define CPP_TCP_MAX_SIZE 1500 //In accordance with MTU definitoins

class DLLCPP_API CSERVER {
public:
    /**
     * default constructor
     */
    CSERVER ();
    /**
     * default destructor
     */
    virtual ~CSERVER ();

    /**! \fn int Create(unsigned int uiPort, bool bClbk);
    *   \brief creates singleton socket listener
    *   creates singleton socket listener, which is invoked within dedicated thread
    *   if bClbk is true, otherwise within the main thread.
    *   \param uiPort socket listener port
    *   \param fnClbk call-back function address. if not NULL then callback mode of operation. otherwise normal.
    *   \return 0 on success, error id otherwise.
    */
    int registerCallback(unsigned int uiPort, SOCK_CLBK fnClbk=NULL, int iMsgMaxSize=512)throw (CMException);
….
…
Send()…
….
...

protected:
#ifndef WIN32
    friend void* _fnTCPClbkThread(void *);  //call-back argument for pthread_create within RunClbkThread.
#else
    friend DWORD WINAPI _fnTCPClbkThread( LPVOID lpParam );
#endif

    /**! \fn int IsPending(int iSock, bool& bFail)
     * \brief check pending connection on a non blocking socket
     *  actuall checks for errors and whether or not connection is ready for write operation.
     * \param iSock client socket connection to check.
     * \return: OK (0) if iSock ready for write operation or ERROR otherwise (still pending for instance)
     */
    int IsPending(int iSock)throw (CMException);
    int RunClbkThread();
    int CreateClbk()throw (CMException);
    void ClbkThread();
private:
    typedef void (CSERVER::*PCLBKTHREAD)(void *);
    PCLBKTHREAD _pThreadClbk;
    int     _iServerSock;
    int     _iSock;         
    SOCK_CLBK   _fnClbk;
    unsigned int _uiPort;
    int _iAddrLen;
    bool _bClbkThreadAlive;
    int _iClientConnectionsArr[CPP_TCP_MAX_CLIENTS];
    int _iMsgMaxSize;
    struct sockaddr_in  _saddConnect ;
#ifdef WIN32
    WSADATA m_wsaData;
    HANDLE  _thread;
#else
    pthread_t _thread;
#endif

};
#包括“CSocket.h”
#ifndef WIN32
#包括
#否则
#包括
#包括
#恩迪夫
#定义CPP_TCP_MAX_客户端17
#根据MTU定义定义CPP\U TCP\U最大尺寸1500//
类DLLCPP_API CSERVER{
公众:
/**
*默认构造函数
*/
CSERVER();
/**
*默认析构函数
*/
virtual~CSERVER();
/**!\fn int-Create(未签名的int-uiPort,bool-bClbk);
*\brief创建单例套接字侦听器
*创建在专用线程中调用的单例套接字侦听器
*如果bClbk为true,则在主线程中为true。
*\param uiPort套接字侦听器端口
*\param fnClbk回调函数地址。如果不为NULL,则返回操作模式。否则为正常。
*\成功返回0,否则返回错误id。
*/
int registerCallback(未签名的int-uiPort,SOCK_-CLBK-fnClbk=NULL,int-iMsgMaxSize=512)抛出(CMException);
….
…
发送()…
….
...
受保护的:
#ifndef WIN32
friend void*\u fnTCPClbkThread(void*);//在RunClbkThread中创建pthread的回调参数。
#否则
friend DWORD WINAPI_fnTCPClbkThread(LPVOID lpParam);
#恩迪夫
/**!\fn内部显示(int iSock、bool和bFail)
*\简要检查非阻塞套接字上的挂起连接
*actuall检查错误以及连接是否准备好进行写入操作。
*\param要检查的iSock客户端套接字连接。
*\return:如果iSock已准备好写入操作,则返回OK(0),否则返回错误(例如,仍挂起)
*/
int IsPending(int iSock)throw(CMException);
int RunClbkThread();
int CreateClbk()抛出(CMException);
void ClbkThread();
私人:
typedef void(CSERVER::*PCLBKTHREAD)(void*);
pclbkthreadpthreadclbk;
int_iServerSock;
int_iSock;
SOCK_CLBK_fnClbk;
无符号整数端口;
国际数据中心;
bool_bclbkthread live;
int_IClientConnectionsAR[CPP_TCP_MAX_客户端];
int_iMsgMaxSize;
连接中的结构sockaddr\u;
#ifdef WIN32
WSADATA m_WSADATA;
手柄(螺纹),;
#否则
pthread_t_线程;
#恩迪夫
};
查看函数寄存器回调
从中我可以推断,该类没有存储任何用户数据,稍后将作为回调参数传递……为什么它们有可变模板呢?不知道。

首先,您使用
ReadTCP
函数模板的代码是不正确的。
SOCK\u CLBK
是一种函数指针,它的参数列表末尾有一个ich不同于
ReadTCP
拥有的
int
(或任何其他类型)。编译器不会编译失败,因为您将指向
ReadTCP
的指针显式转换为
SOCK\u CLBK
,但调用在运行时失败(您在
int a
参数中收到随机值或崩溃)

使用
std::bind
的第二段代码也是错误的,因为
std::bind
返回函数对象,而不是函数指针。函数对象具有
operator()
,因此它可以像函数一样调用,但不能转换为函数指针(首先,因为对象也包含数据,比如绑定的参数)

您必须定义一个接受可变数量参数的函数(即在其参数列表末尾有一个省略号),并将该函数作为回调传递。在该函数中,您可以处理传递的参数,并可能调用代码中的其他专用函数,如
ReadTCP

int ReadTCPCallback(int socket, short code, unsigned char* msg, int received, ...)
{
    std::va_list args;
    va_start(args, received);

    // Use variable arguments here, using va_arg. Consult with the API
    // documentation to know what arguments are expected here. For the sake
    // of this example, let's assume an int argument is passed.
    int n = va_arg(args, int);

    int res = ReadTCP(socket, code, msg, received, n);

    // Always call va_end before returning once you're done with va_list
    va_end(args);

    return res;
}
如果要在此API中使用函数对象,则必须找到通过第三方库将指向数据的指针传递给回调的方法。该数据将包含绑定参数和与调用相关的其他状态。有关如何将用户数据传递给回调,请参阅该第三方库的文档


如果API不支持传递用户数据(这将使其成为一个设计相当糟糕的API),则可以将数据与API返回的与您的状态对应的句柄相关联。例如,您可以维护一个全局
std::map
,以映射套接字文件描述符(
int
)指向指向与该套接字或连接相关的数据的指针。

您需要处理C-省略号。模板函数不匹配。简单地强制转换函数指针并那样调用它是无效的。回调函数需要是可变的,而不仅仅是在那里预期一个
int
。然后您需要将其作为适当的C-样变量处理C函数+ C++模板函数与C函数不相同。避免C抛出:<代码>(Sokkl CbBk)(…)/Calp>。如果提供正确的函数,则不需要抛出。也许提供链接到第三个库……谢谢安德烈,现在我确信我一开始就做的很好。我用STD::