【发布时间】:2017-09-09 19:17:46
【问题描述】:
我正在通过做一些练习来学习可变参数模板,但当涉及到 lambda 中的参数包扩展时,我被卡住了
所以,我的想法是编写一个计时器类,其有效负载将是可调用的,但是当我尝试在 lambda 函数中展开参数包时出现编译错误..
gcc 版本 4.8.4 (Ubuntu 4.8.4-2ubuntu1~14.04.3)
template<typename F, typename... Args>
struct timer
{
timer(const std::chrono::milliseconds milliseconds, F call, Args&&... args)
{
m_timer = std::make_shared<boost::asio::steady_timer>(
timer_manager::instance().get_io_service(),
std::chrono::steady_clock::now() + milliseconds
);
//m_timer->async_wait(call, std::forward<Args>(args)...);
m_timer->async_wait([=](const boost::system::error_code& ec){
call(std::forward<Args>(args)...); //Error here
});
}
std::shared_ptr<boost::asio::steady_timer> m_timer;
};
// Helper to create the timer
template<typename F, typename... Args>
timer<F,Args...> create_timer(const std::chrono::milliseconds milliseconds,F callable, Args&& ...args)
{
return timer<F,Args...>(milliseconds, std::forward<F>(callable), std::forward<Args>(args)...);
}
使用它的主程序:
auto timer = timer::create_timer(std::chrono::milliseconds(5000), []()
{
std::cout << "timer fired in main" << std::endl;
payload::execute(10);
});
错误:
home/samdaniel/timer/src/timer.hpp: In lambda function:
/home/samdaniel/timer/src/timer.hpp:36:43: error: parameter packs not expanded with ‘...’:
call(std::forward<Args>(args)...);
^
/home/samdaniel/timer/src/timer.hpp:36:43: note: ‘args’
/home/samdaniel/timer/src/timer.hpp: In instantiation of ‘struct timer::timer<F, Args>::timer(std::chrono::milliseconds, F, Args&& ...) [with F = main()::__lambda1; Args = {}; std::chrono::milliseconds = std::chrono::duration<long int, std::ratio<1l, 1000l> >]::__lambda0’:
/home/samdaniel/timer/src/timer.hpp:35:10: required from ‘timer::timer<F, Args>::timer(std::chrono::milliseconds, F, Args&& ...) [with F = main()::__lambda1; Args = {}; std::chrono::milliseconds = std::chrono::duration<long int, std::ratio<1l, 1000l> >]’
/home/samdaniel/timer/src/timer.hpp:50:99: required from ‘timer::timer<F, Args ...> timer::create_timer(std::chrono::milliseconds, F, Args&& ...) [with F = main()::__lambda1; Args = {}; std::chrono::milliseconds = std::chrono::duration<long int, std::ratio<1l, 1000l> >]’
/home/samdaniel/src/main.cpp:21:11: required from here
/home/samdaniel/timer/src/timer.hpp:36:43: error: using invalid field ‘timer::timer<F, Args>::timer(std::chrono::milliseconds, F, Args&& ...)::__lambda0::__args’
make[2]: *** [src/CMakeFiles/coding_with_me.dir/main.cpp.o] Error 1
make[1]: *** [src/CMakeFiles/coding_with_me.dir/all] Error 2
make: *** [all] Error 2
新示例:
#include <iostream>
#include <functional>
namespace test
{
template<typename F, typename... Args>
void callback_dispatcher(F call, Args&& ...args )
{
std::cout << "callback_dispatcher>" << __PRETTY_FUNCTION__ << "enter <<< " << std::endl;
auto invoke_me = [=](){
call(std::forward<Args>(args)...);
};
invoke_me();
}
}
int main()
{
std::cout << "Main entered..." << std::endl;
test::callback_dispatcher([](int a)
{
std::cout << "void(int) lambda dispatched with a = " << a << std::endl;
},5);
std::cout << "Main exited..." << std::endl;
}
错误:
src/generic_callback.cc: In lambda function:
src/generic_callback.cc:11:34: error: parameter packs not expanded with ‘...’:
call(std::forward<Args>(args)...);
^
src/generic_callback.cc:11:34: note: ‘args’
src/generic_callback.cc: In instantiation of ‘struct test::callback_dispatcher(F, Args&& ...) [with F = std::_Bind<std::_Mem_fn<void (plo_callback_tester::*)()>(std::_Placeholder<1>)>; Args = {plo_callback_tester* const}]::__lambda0’:
src/generic_callback.cc:12:7: required from ‘void test::callback_dispatcher(F, Args&& ...) [with F = std::_Bind<std::_Mem_fn<void (plo_callback_tester::*)()>(std::_Placeholder<1>)>; Args = {plo_callback_tester* const}]’
src/generic_callback.cc:25:101: required from here
src/generic_callback.cc:11:34: error: using invalid field ‘test::callback_dispatcher(F, Args&& ...)::__lambda0::__args’
src/generic_callback.cc: In instantiation of ‘struct test::callback_dispatcher(F, Args&& ...) [with F = main()::__lambda1; Args = {int}]::__lambda0’:
src/generic_callback.cc:12:7: required from ‘void test::callback_dispatcher(F, Args&& ...) [with F = main()::__lambda1; Args = {int}]’
src/generic_callback.cc:41:13: required from here
src/generic_callback.cc:11:34: error: using invalid field ‘test::callback_dispatcher(F, Args&& ...)::__lambda0::__args’
【问题讨论】:
-
我不确定(这就是为什么这是评论而不是答案),但我认为你想做
std::forward<Args...>(args...);即,将...移动到括号和模板参数列表中。我认为这里也不需要模板参数,但我又不确定。 -
@DanielH: 不,如果
Args&&...是转发参考包,std::forward<Args>(args)...将是正确的。在构造函数中std::move(args)...就足够了。 -
coliru.stacked-crooked.com/a/b291d1dff8829497 -- 在消除不应该改变错误的东西之后,这些编译器中的任何一个都没有错误。请提供一个实际的minimal reproducible example,它既能重现问题,又能消除所有那些额外不重要的依赖关系。除非你认为
timer_manager和所有的 asio 东西实际上会导致参数包不扩展错误,我不相信。诚然,这些是编译器的更高版本,但我会让你在你的编译器中生成minimal reproducible example,而不是试图读懂你的想法。 -
@Yakk,向用作回调的 lambda 添加一个参数,然后事情就中断了 - coliru.stacked-crooked.com/a/15c0bf4fc22316e6 ,但我不确定在捕获期间参数包的类型会发生什么情况在 lambda 旁边以及它为什么会中断:(
-
但是,是的,删除 lambda 中似乎不需要的
std::forward可以解决参数问题。忽略我之前的评论。
标签: c++ c++11 lambda variadic-templates