如何实现variadic虚拟成员函数

Dan*_*iaz 9 c++ parameters variadic-functions c++11

所以我有这个功能......

virtual void CallRemoteFunction( const char* pServerGameObjectId, const char* pFunctionName, OVariant arg1 = OVariant(), OVariant arg2 = OVariant(), OVariant arg3 = OVariant(), OVariant arg4 = OVariant(), OVariant arg5 = OVariant(), OVariant arg6 = OVariant(), OVariant arg7 = OVariant(), OVariant arg8 = OVariant(), OVariant arg9 = OVariant() );
Run Code Online (Sandbox Code Playgroud)

我决定重写这个功能,因为坦白说,我很尴尬.该函数很简单......采用可变数量的未知类型的参数并执行操作.

我对现代C++很新,所以我做了一些搜索,并假设我会找到一些简单/优雅的新方法.我想象了......

//hypothetical code
virtual void CallRemoteFunction( const char* pServerGameObjectId, const char* pFunctionName, ... args )
{
    std::vector<OVariant> argsArray;
    for (auto& arg : args )
    {
        argsArray.push_back(arg)
    }

    //do other stuff
 }
 //end hypothetical code
Run Code Online (Sandbox Code Playgroud)

但在我的搜索中,我找不到任何接近的东西.那么有人可以给我一些关于如何将我的原始函数重构为更简洁的东西的想法吗?注意:解决方案必须是C++ 11或更早版本.

-Update-该功能不必是虚拟的.
我希望能够像这样调用函数...

CallRemoteFunction("serverID","someFunc",1,2,3);
Run Code Online (Sandbox Code Playgroud)

以下是实施参考

//calls function on client if this peer is a linked server or vice versa
void Peer::CallRemoteFunction( const char* pServerGameObjectId,  const char* 
pFunctionName, OVariant arg1, OVariant arg2, OVariant arg3, OVariant arg4, 
OVariant arg5, OVariant arg6, OVariant arg7, OVariant arg8, OVariant arg9 )
{
    Command command;
    command.SetObjectName( pServerGameObjectId );
    command.SetFunctionName( pFunctionName );
    command.ResetArgs();
    if ( arg1.IsValid() ){ command.PushArg( arg1 ); }
    if ( arg2.IsValid() ){ command.PushArg( arg2 ); }
    if ( arg3.IsValid() ){ command.PushArg( arg3 ); }
    if ( arg4.IsValid() ){ command.PushArg( arg4 ); }
    if ( arg5.IsValid() ){ command.PushArg( arg5 ); }
    if ( arg6.IsValid() ){ command.PushArg( arg6 ); }
    if ( arg7.IsValid() ){ command.PushArg( arg7 ); }
    if ( arg8.IsValid() ){ command.PushArg( arg8 ); }
    if ( arg9.IsValid() ){ command.PushArg( arg9 ); }

    LOG_DEBUG( "Calling Remote Function : " << pServerGameObjectId << "." << 
command.GetFunctionName() );
    ByteArray buffer( command.GetSerializeSize() );
    command.Serialize( buffer );

    ZMQMessage* request = new ZMQMessage();//deleted when sent via zmq
    request->addmem( buffer.GetBytes(), buffer.m_NumBytes );

    PushMessage( MDPW_REQUEST, m_pServiceId, request );
}
Run Code Online (Sandbox Code Playgroud)

Rei*_*ica 6

如果您愿意接受稍微不同的调用语法(例如std::max也使用),您可以拥有一个非常优雅的解决方案:

virtual void CallRemoteFunction( const char* pServerGameObjectId, const char* pFunctionName, std::initializer_list<QVariant> args )
{
    std::vector<OVariant> argsArray;
    for (auto& arg : args )
    {
        argsArray.push_back(arg)
    }

    //do other stuff
}
Run Code Online (Sandbox Code Playgroud)

这样称呼:

CallRemoteFunction("foo", "bar", { arg1, arg2, arg3 });
Run Code Online (Sandbox Code Playgroud)


Ded*_*tor 6

当然,如果你愿意,你可以拥有它.您只需要将模板化转发器与非模板化虚拟函数组合在一起.

我正在使用gsl::span(" 什么是"跨度"我何时应该使用? ")和自动std::array(不是本机的,以避免0的特殊情况)以获得最佳的通用性,稳定性和效率.

virtual void DoCallRemoteFunction(
    const char* pServerGameObjectId,
    const char* pFunctionName,
    gsl::span<OVariant> args
) {
    ...
}

template<class... ARGS>
void CallRemoteFunction(
    const char* pServerGameObjectId,
    const char* pFunctionName,
    ARGS&&... args
) {
    std::array<OVariant, sizeof...(ARGS)> arr = { OVariant{std::forward<ARGS>(args)} ... };
    DoCallRemoteFunction(pServerGameObjectId, pFunctionName, arr);
}
Run Code Online (Sandbox Code Playgroud)

我给了他们不同的名字,因为你可能会覆盖虚函数,并且可能不希望API函数被遮蔽.