Why does GCC produce a weird error and try to call the wrong method when the template arguments are explicitly specified?

I had a submitAsync function that took a template std::function as a parameter:

 template <typename Ret, typename... Args> Future<Ret> submitAsync(const function<Ret (Args...)> &func, Args&&... args); 

However, the implicit derivation of the template argument did not work when passing the lambda (similar to the problem here , so I had to make a more general function that took as a template parameter, 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 using Clang, but with GCC, the following error is returned:

 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 call submitAsync(const function<Ret (Args...)> &, Args&&...) , is actually trying to call submitAsync(Func &&func, Args&&... args) , which of course does not work, since func passed int type. The last part of the error, which I also don’t understand, is expansion pattern '#'nontype_argument_pack' not supported by dump_expr#<expression error>' contains no argument packs , which may be a compiler error (line 82 is the main part of the function signature, where I put the comment to tag her)?

Oddly enough, when I remove explicit template parameters in a 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 does GCC call the wrong function when specifying template arguments, even if it works fine when arguments are allowed? And can anyone tell me what a strange mistake on line 82?

Edit: Forgot to mention, I'm using GCC 4.7.2

EDIT 2: solution and explanation here

+8
c ++ gcc c ++ 11 templates
source share
1 answer

During further testing, I realized that both Clang and GCC without explicit template parameters actually do not work as I wanted. In both cases, the function simply called itself the first function that matches the parameters. This was caused by a compiler deciding submitAsync , which takes a function as a template parameter, was better than one that takes const std::function& . Now it works fine after changing this submitAsync to execute the function by reference:

 template <typename Ret, typename... Args> Future<Ret> Scheduler::submitAsync(function<Ret (Args...)> func, Args&&... args) 
+1
source share

All Articles