参数包扩展在Lambda中不起作用 [英] parameter pack expansion not working in lambda
问题描述
我通过做一些练习来学习可变参数模板,但是在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’
#include <iostream>
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 = [=]()mutable{
call(std::move(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;
}
上述轻微更改在gcc 4.9及更高版本中进行了编译,但在gcc 4.8.5中未进行编译.
它也可以在现代版本的clang中进行编译.
更新您的编译器,或者不使用您的编译器不支持的c ++ 11功能.
您也许可以将args打包成一个元组,然后将它们解压缩到函数的主体中.
template<typename F, typename... Args>
void callback_dispatcher(F call, Args&& ...args )
{
std::cout << "callback_dispatcher>" << __PRETTY_FUNCTION__ << "enter <<< " << std::endl;
auto invoke_me = [tup = std::make_tuple(std::forward<Args>(args)...), call=std::move(call)]()mutable{
std::apply( call, std::move(tup) );
};
invoke_me();
}
现在您必须在C ++ 11的有限子集中实现std::apply
,这是C ++ 17的功能. (不要称它为std::apply
).这种方法可能会在g ++ 4.8中起作用.
namespace notstd {
template<std::size_t...Is> struct index_sequence {using type=index_sequence;};
template<std::size_t N, std::size_t...Is> struct make_index_sequence:make_index_sequence<N-1, N-1, Is...>{};
template<std::size_t...Is> struct make_index_sequence<0,Is...>:index_sequence<Is...>{};
namespace details {
template<class F, class Tuple, std::size_t...Is>
auto apply( ::notstd::index_sequence<Is...>, F&& f, Tuple&& tuple )
-> decltype( std::declval<F>()( std::get<Is>(std::declval<Tuple>())... ) )
{
return std::forward<F>(f)( std::get<Is>(std::forward<Tuple>(tuple))... );
}
}
template<class F, class Tuple>
auto apply( F&& f, Tuple&& tuple )
-> decltype(::notstd::details::apply( make_index_sequence<std::tuple_size<typename std::decay<Tuple>::type>::value>{}, std::forward<F>(f), std::forward<Tuple>(tuple) ))
{
return ::notstd::details::apply( make_index_sequence<std::tuple_size<typename std::decay<Tuple>::type>::value>{}, std::forward<F>(f), std::forward<Tuple>(tuple) );
}
}
符合C ++ 11的notstd :: apply 的实时示例.. >
I am learning variadic templates by doing some exercises and I am stuck when it comes to parameter pack expansion in lambda
So, my idea is to write a timer class whose payload will be callable, But I get a compilation error when I try to expand the parameter pack inside a lambda function..
gcc version 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)...);
}
Main program to use it:
auto timer = timer::create_timer(std::chrono::milliseconds(5000), []()
{
std::cout << "timer fired in main" << std::endl;
payload::execute(10);
});
Error:
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
New example:
#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;
}
Error:
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’
#include <iostream>
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 = [=]()mutable{
call(std::move(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;
}
The above slight change compiles in gcc 4.9 and up, but not in gcc 4.8.5.
It also compiles in modern versions of clang.
Update your compiler, or don't use c++11 features that your compiler doesn't support.
You may be able to pack your args into a tuple, then unpack them in the body of the function.
template<typename F, typename... Args>
void callback_dispatcher(F call, Args&& ...args )
{
std::cout << "callback_dispatcher>" << __PRETTY_FUNCTION__ << "enter <<< " << std::endl;
auto invoke_me = [tup = std::make_tuple(std::forward<Args>(args)...), call=std::move(call)]()mutable{
std::apply( call, std::move(tup) );
};
invoke_me();
}
where you now have to implement std::apply
, which is a C++17 feature, in the limited subset of C++11 you have. (Don't call it std::apply
). This approach will probably work in g++ 4.8.
namespace notstd {
template<std::size_t...Is> struct index_sequence {using type=index_sequence;};
template<std::size_t N, std::size_t...Is> struct make_index_sequence:make_index_sequence<N-1, N-1, Is...>{};
template<std::size_t...Is> struct make_index_sequence<0,Is...>:index_sequence<Is...>{};
namespace details {
template<class F, class Tuple, std::size_t...Is>
auto apply( ::notstd::index_sequence<Is...>, F&& f, Tuple&& tuple )
-> decltype( std::declval<F>()( std::get<Is>(std::declval<Tuple>())... ) )
{
return std::forward<F>(f)( std::get<Is>(std::forward<Tuple>(tuple))... );
}
}
template<class F, class Tuple>
auto apply( F&& f, Tuple&& tuple )
-> decltype(::notstd::details::apply( make_index_sequence<std::tuple_size<typename std::decay<Tuple>::type>::value>{}, std::forward<F>(f), std::forward<Tuple>(tuple) ))
{
return ::notstd::details::apply( make_index_sequence<std::tuple_size<typename std::decay<Tuple>::type>::value>{}, std::forward<F>(f), std::forward<Tuple>(tuple) );
}
}
live example of C++11 compliant notstd::apply.
这篇关于参数包扩展在Lambda中不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!