Here is a the minimal example I was able to come up with:
#include <utility>
template<class CB, class... ARGS>
void call_lam(CB&& cb, ARGS&&... args) {
auto lam = [&args...](auto&& callee) {
callee(std::forward<ARGS>(args)...);
};
lam(cb);
}
void exec(unsigned, int);
void foo() {
unsigned x = 25;
int y = 0;
call_lam(exec, x, y);
}
Above example compiles with both CLang and gcc, but failes with icc 17.0 (as https://godbolt.org/g/tzMY6K shows). The error is as following:
/usr/include/c++/5/bits/move.h(89): error: static assertion failed with "template argument substituting _Tp is an lvalue reference type"
static_assert(!std::is_lvalue_reference<_Tp>::value, "template argument"
^ detected during:
instantiation of "_Tp &&std::forward<_Tp>(std::remove_reference<_Tp>::type &&) [with _Tp=unsigned int &]" at line 5 of ""
instantiation of function "lambda [](auto &&)->auto [with =void (&)(unsigned int, int)]" at line 7 of ""
instantiation of "void call_lam(CB &&, ARGS &&...) [with CB=void (&)(unsigned int, int), ARGS=]" at line 15 of "" compilation aborted for (code 2)
Compiler exited with result code 2
Playing with this example, I have found out that:
- It has to be to distinct types as arguments to
exec
. When using two ints or a single argument, the error goes away - by replacing the types with something else (for example,
std::string
) and changing manner of passing arguments toexec
(const&
) the error can be reported as something else, saying that "overload forstd::move
can not be matched". At this point, it would also fail on icc16. This is slightly modified code: https://godbolt.org/g/qHrU6P
Provided the code is well-formed (as I believe it is), other than replacing lambda with a custom functor (which I do not want to do, as I do not want to capture variable number of arguments with proper references manually through tuples) does anybody see any workarounds here?
I think below code will meet your workaround requirements: