如果已在其他地方回答了此问题,表示歉意,我确实搜索过,但找不到明确的匹配项。C++ 11可变参数模板类中的可变参数函数不能按预期方式工作
我在模板类中有一个可变参数函数,它不能像我期望的那样工作。我有一个解决方法,但我怀疑这不是最好的解决方案。
考虑下面的代码:
#include <iostream>
#include <functional>
#include <vector>
template< typename... ARGS >
class Kitten
{
public:
using Callback = std::function< void(ARGS&&...) >;
Kitten() = default;
void addCallback(Callback && c)
{
callbacks.push_back(std::forward<Callback>(c));
}
void processCallbacks(ARGS &&... args)
{
for (Callback const &c : callbacks)
{
c(std::forward<ARGS>(args)...);
}
}
private:
std::vector<Callback> callbacks;
};
int main(int argc, const char * argv[])
{
(void) argc;
(void) argv;
Kitten<int, float> kitty;
kitty.addCallback([](int i, float f)
{
std::cout << "Int: " << i << "\nFloat: " << f << "\n";
});
kitty.processCallbacks(2, 3.141f);
int ii = 54;
float ff = 2.13f;
kitty.processCallbacks(ii, ff);
return 0;
}
这不会编译,第二次调用processCallbacks会产生一个错误(铛,看到VCl 4类似的问题)。
我可以修复编译和得到的东西,如果我改变processCallbacks到定义为预期工作:
template< typename... FORCEIT >
void processCallbacks(FORCEIT &&... args)
{
for (Callback const &c : callbacks)
{
c(std::forward<ARGS>(args)...);
}
}
在我看来是有点俗气的解决办法,即使它似乎工作,我怀疑我错过了一个更好的解决方案。
我对第一个示例失败原因的理解是因为没有对参数包进行类型推导,所以编译器不会为所有情况生成正确的代码。第二个示例的工作原理是因为它强制参数包中的类型扣除。
这一直困扰着我一段时间。任何帮助非常感谢。
编辑:VC12编译器错误:
error C2664: 'void Kitten<int,float>::processCallbacks(int &&,float &&)' : cannot convert argument 1 from 'int' to 'int &&'
编辑:苹果LLVM版本7.0.0编译器错误:
error: rvalue reference to type 'int' cannot bind to lvalue of type 'int'
关于变化的意见建议使用std::move
,addCallback
似乎在形式上更加灵活:
template< typename FUNCTION >
void addCallback(FUNCTION && c)
{
callbacks.emplace_back(std::forward<FUNCTION>(c));
}
使用std::forward
,因为该功能现在需要通用参考。 由于这将允许以下工作:
std::function< void(int, float)> banana([](int i, float f)
{
std::cout << "Int: " << i << "\nFloat: " << f << "\n";
});
kitty.addCallback(banana);
你应该发布你的编译器错误。 – TartanLlama
'std :: forward < Callback >(c)'等于'std :: move(c)' –
大概我还应该使用'emplace_back'来提高效率? – Slartibartfast