2016-01-18 21 views
0

我需要一个具有可变数量参数的模板函数。目前我的问题是通过使用几个模板函数来解决的。但是现在我需要在我的类函数中做一个包装方法,以及将这些代码打包到一个函数中的其他原因。我需要一个具有可变数量参数的模板函数

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':参数包必须在这方面

+6

尚未[可变参数模板参数包(http://en.cppreference.com/w/cpp/language/parameter_pack)的帮你吗? –

回答

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

rvalues存在问题:无法将参数3从'bool'转换为'bool'' – Ufx

+0

但是,如果将Targs&Targs &&和T&更改为T &&它可以工作。这是好的解决方案吗? – Ufx

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()来编写手卷结构。

这并不代替零参数的情况下,自然,并给出你的代码是多么短,我不会扭曲自己到pretzils来处理它。


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

假设你有一个C++ 14的λ,看起来像这样:

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

与模板operator()把它变成一个C++ 11函数对象,首先确定你捕捉每个实际的事情,手动捕获它们。假设/* code */使用名称bobalice并隐式使用this。然后重写这样的行:

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

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

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

下一步是计算出bobalicethis的类型。假设它们是BobAliceMyClass。创建一个类似如下的类:

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 */ 
    } 
}; 

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

将这个类之前你的函数你在哪里使用在lambda

改写原线。

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

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

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

+1

这不需要尾部参数是全部相同的类型,而在原始代码中,1,2或3个参数可以是所有不同的类型? –

+0

@JonathanLeffler否:所有类型都通过'Ts'转发到lambda。 – Quentin

+0

'void for_each_arg(F && f,Ts && ts){' - 错误C3520:'Ts':参数包必须在此上下文中扩展 – Ufx

0

您可以

template<typename... Targs> 
void flush(OByteStream &obs, Targs... Fargs) 
{ 
    using swallow = int[sizeof...(Targs)]; 
    (void) swallow{(obs << Fargs, 0)...}; 
} 

该技术避免了递归更换这两个冲水功能。当然,你可以更换obs << Fargs与任何函数调用,您需要:

template<typename Callable, typename... Targs> 
void call_for_each(Callable&& callable, Targs... Fargs) 
{ 
    using swallow = int[sizeof...(Targs)]; 
    (void) swallow{(callable(Fargs), 0)...}; 
}