我需要一个带有可变数量参数的模板函数

Ufx*_*Ufx 0 c++ c++11 c++14

我需要一个带有可变数量参数的模板函数.目前我的问题通过使用几个模板函数来解决.但是现在我需要在我的类函数和其他原因中创建一个wrap方法来将这个代码打包到一个函数中.

static void sendData(SSL *ssl, Command com)
{
    std::string comStr(COM_SIZE, ' ');
    memcpy(&comStr[0], &com, COM_SIZE);
    sslWrite(ssl, comStr);
}

template<class T>
void sendData(SSL *ssl, Command com, const T &t)
{
    std::string serialArg;
    OByteStream obs(serialArg);
    obs << t;
    obs.flush();

    const int serialArgSize = serialArg.size();
    std::string comAndSerialData(COM_SIZE + serialArgSize, ' ');
    memcpy(&comAndSerialData[0], &com, COM_SIZE);
    memcpy(&comAndSerialData[COM_SIZE], &serialArg[0], serialArgSize);

    sslWrite(ssl, comAndSerialData);
}

template<class T1, class T2>
void sendData(SSL *ssl, Command com, const T1 &t1, const T2 &t2)
{
    std::string serialArgs;
    OByteStream obs(serialArgs);
    obs << t1 << t2;
    obs.flush();

    const int serialArgsSize = serialArgs.size();
    std::string comAndSerialData(COM_SIZE + serialArgsSize, ' ');
    memcpy(&comAndSerialData[0], &com, COM_SIZE);
    memcpy(&comAndSerialData[COM_SIZE], &serialArgs[0], serialArgsSize);

    sslWrite(ssl, comAndSerialData);
}

template<class T1, class T2, class T3>
void sendData(SSL *ssl, Command com, const T1 &t1, const T2 &t2, const T3 &t3)
{
    std::string serialArgs;
    OByteStream obs(serialArgs);
    obs << t1 << t2 << t3;
    obs.flush();

    const int serialArgsSize = serialArgs.size();
    std::string comAndSerialData(COM_SIZE + serialArgsSize, ' ');
    memcpy(&comAndSerialData[0], &com, COM_SIZE);
    memcpy(&comAndSerialData[COM_SIZE], &serialArgs[0], serialArgsSize);

    sslWrite(ssl, comAndSerialData);
}

//...
Run Code Online (Sandbox Code Playgroud)

我怎么能在一个函数中写这个?


这是我尝试使用可变参数模板

void flush(OByteStream &obs)
{
    obs.flush();
}

template<typename T, typename... Targs>
void flush(OByteStream &obs, T value, Targs... Fargs)
{
    obs << value;
    flush(obs, Fargs);
}

template<typename... Targs>
void sendData(SSL *ssl, Command com, Targs... Fargs)
{
    std::string serialArgs;
    OByteStream obs(serialArgs);
    flush(obs, Fargs);

    const int serialArgsSize = serialArgs.size();
    std::string comAndSerialData(COM_SIZE + serialArgsSize, ' ');
    memcpy(&comAndSerialData[0], &com, COM_SIZE);
    memcpy(&comAndSerialData[COM_SIZE], &serialArgs[0], serialArgsSize);

    sslWrite(ssl, comAndSerialData);
}
Run Code Online (Sandbox Code Playgroud)

flush(obs, Fargs); - 错误C3520:'Fargs':必须在此上下文中扩展参数包

Yak*_*ont 6

template<class...Ts>
void sendData(SSL *ssl, Command com, const Ts&... ts)
Run Code Online (Sandbox Code Playgroud)

...用以下内容替换<<:

for_each_arg([&](auto&&t){obs << t;},ts...);
Run Code Online (Sandbox Code Playgroud)

for_each_arg:

template<class F,class...Ts>
void for_each_arg(F&&f, Ts&&... ts){
  using discard=int[];
  (void)discard{ 0, ((
    f(std::forward<Ts>(ts))
  ),void(),0)...}
}
Run Code Online (Sandbox Code Playgroud)

这是神秘而有效的.

这在C++ 11上变得更难,因为你没有auto&&lambdas.您可以使用模板编写手动结构operator().

这自然不会取代零arg情况,并且鉴于你的代码有多短,我不会把自己扭曲成pretzils来处理它.


如何使用模板运算符()替换C++ 14自动lambda来编写C++ 11函数对象?

假设您有一个C++ 14 lambda,如下所示:

auto f = [&](auto&& x) { /* some code */ };
Run Code Online (Sandbox Code Playgroud)

使用模板将其转换为C++ 11函数对象operator(),首先标识要捕获的每个实际内容,然后手动捕获它们.假设/* code */使用了名称bob alice并隐式使用this.然后重写这样的行:

auto f = [&bob, &alice, this](auto&& x) { /* some code */ };
Run Code Online (Sandbox Code Playgroud)

在那里我们列出我们捕获的一切

接下来,采取明确的/* some code */每一种用法.如果我们使用,请替换它.this m_xthis->m_x

下一步是弄清楚bob alice和的类型this.假设他们是Bob AliceMyClass.创建一个类似于的类:

struct function_object_f {
  Bob const& bob;
  Alice const& alice;
  MyClass* self;
};
Run Code Online (Sandbox Code Playgroud)

按顺序捕获变量.现在添加一个template operator():

struct function_object_f {
  Bob const& bob;
  Alice const& alice;
  MyClass* self;
  template<class X>
  void operator()(X&& x)const {
    /* some code */
  }
};
Run Code Online (Sandbox Code Playgroud)

现在,取代的每一个明确提及this/* some code */self.

把这个类放在你使用lambda的函数之前.

重写原始行:

auto f = function_object_f{bob, alice, this};
Run Code Online (Sandbox Code Playgroud)

我们完成了.(请注意,捕获的顺序在这里很重要:它必须与function_object_f成员变量声明匹配). f几乎与lambda相同,但它的类型有一个名字.

(对于no-capture lambdas,它缺少隐式转换为函数的指针,但这是另一天的样板).