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

时间:2016-01-18 00:16:49

标签: 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);
}

//...

我如何在一个函数中写这个?

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

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);
}

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

3 个答案:

答案 0 :(得分:6)

template<class...Ts>
void sendData(SSL *ssl, Command com, const Ts&... ts)

... 将<<行替换为:

for_each_arg([&](auto&&t){obs << t;},ts...);

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)...}
}

这是神秘而有效的。

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

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

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

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

auto f = [&](auto&& x) { /* some code */ };

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

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

我们列出我们捕获的所有内容。

接下来,取/* some code */并使用this 明确。如果我们使用m_x,请将其替换为this->m_x

下一步是确定bob alicethis的类型。假设它们是Bob AliceMyClass。创建一个类似于以下的类:

struct function_object_f {
  Bob const& bob;
  Alice const& alice;
  MyClass* self;
};

按顺序捕获变量。现在添加template operator()

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

现在,用this替换/* some code */self的每一个明确提及。

在你的函数之前把这个类放在使用lambda的地方。

重写原始行:

auto f = function_object_f{bob, alice, this};

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

(对于没有捕获的lambdas,它缺少隐式转换为函数的指针,但这是另一天的样板文件。)

答案 1 :(得分:1)

inline 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);
}

答案 2 :(得分:0)

您可以用

替换两个刷新功能
pow_factory = -> (exp) {-> (base) {pow.(base, exp: exp)}}
cube = pow_factory.(3)

这种技术避免了递归。当然,您可以使用您需要的任何函数调用替换template<typename... Targs> void flush(OByteStream &obs, Targs... Fargs) { using swallow = int[sizeof...(Targs)]; (void) swallow{(obs << Fargs, 0)...}; }

obs << Fargs