I had a function submitAsync
which accepted a templated std::function
as a parameter:
template <typename Ret, typename... Args>
Future<Ret> submitAsync(const function<Ret (Args...)> &func, Args&&... args);
However, implicit template argument deduction wasn't working when passing a lambda (similar to the issue here, so I had to make a more generic function that accepted the function as a template parameter, to then pass it to the original function:
template <typename Func, typename... Args>
auto submitAsync(Func &&func, Args&&... args) -> // Line 82, where the strange error occurs
Future<
typename enable_if<
is_convertible<
Func, function<decltype(func(args...)) (Args...) >
>::value , decltype(func(args...))
>::type
> {
typedef decltype(func(args...)) ReturnType;
return submitAsync<ReturnType, Args...>(function<ReturnType (Args...)>(func), forward<Args>(args)...);
}
This compiles fine with Clang, but with GCC returns the following error:
src/Scheduler.hpp: In substitution of ‘template<class Func, class ... Args> Future<typename std::enable_if<std::is_convertible<Func, std::function<decltype (func(MCServer::Scheduler::startThread::args ...))(Args ...)> >::value, decltype (func(args ...))>::type> MCServer::Scheduler::submitAsync(Func&&, Args&& ...) [with Func = int; Args = {}]’:
src/Scheduler.hpp:91:109: required from ‘Future<typename std::enable_if<std::is_convertible<Func, std::function<decltype (func(MCServer::Scheduler::startThread::args ...))(Args ...)> >::value, decltype (func(args ...))>::type> MCServer::Scheduler::submitAsync(Func&&, Args&& ...) [with Func = MCServer::MinecraftServer::init()::<lambda()>&; Args = {}; typename std::enable_if<std::is_convertible<Func, std::function<decltype (func(MCServer::Scheduler::startThread::args ...))(Args ...)> >::value, decltype (func(args ...))>::type = int]’
src/MinecraftServer.cpp:237:37: required from here
src/Scheduler.hpp:82:10: error: expansion pattern ‘#‘nontype_argument_pack’ not supported by dump_expr#<expression error>’ contains no argument packs
This shows firstly that the lines
return submitAsync<ReturnType, Args...>(function<ReturnType (Args...)>(func), forward<Args>(args)...);
which should be calling submitAsync(const function<Ret (Args...)> &, Args&&...)
, is actually trying to call submitAsync(Func &&func, Args&&... args)
, which of course doesn't work as the type of func
being passed is int
.
The last part of the error I also do not understand, expansion pattern ‘#‘nontype_argument_pack’ not supported by dump_expr#<expression error>’ contains no argument packs
which could perhaps be a compiler bug (line 82 is the main part of the function's signature, where I put a comment to mark it)?
Strangely enough, when I remove the explicit template parameters in the call to submitAsync
, replacing this line:
return submitAsync<ReturnType, Args...>(function<ReturnType (Args...)>(func), forward<Args>(args)...);
with this:
return submitAsync(function<ReturnType (Args...)>(func), forward<Args>(args)...);
GCC compiles it correctly. So, why is GCC calling the wrong function when the template arguments are specified, even though it works fine when allowed to deduce the arguments? And can anyone tell me what the strange error on line 82 is?
Edit: Forgot to mention, I'm using GCC 4.7.2
EDIT 2: solution and explanation here
Upon further testing, I've realised that both Clang and GCC without explicit template parameters wasn't actually working as I wished. In both cases, the function was just calling itself as the first function that fit the parameters. It was caused by the compiler deciding the submitAsync
that takes the function as a template parameter was a better match than the one taking a const std::function&
. It works fine now after changing that submitAsync
to take the function by reference:
template <typename Ret, typename... Args>
Future<Ret> Scheduler::submitAsync(function<Ret (Args...)> func, Args&&... args)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With