为什么GCC会产生一个奇怪的错误,并在明确指定模板参数时尝试调用错误的方法?

时间:2012-10-15 17:08:00

标签: c++ templates gcc c++11

我有一个函数submitAsync,它接受​​一个模板std::function作为参数:

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

但是,传递lambda时隐式模板参数推导不起作用(类似于问题here,所以我不得不创建一个更通用的函数,接受函数作为模板参数,然后传递它到原来的功能:

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)...);
}

这与Clang编译良好,但GCC返回以下错误:

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

首先显示行

return submitAsync<ReturnType, Args...>(function<ReturnType (Args...)>(func), forward<Args>(args)...); 

应该调用submitAsync(const function<Ret (Args...)> &, Args&&...),实际上是在尝试调用submitAsync(Func &&func, Args&&... args),这当然不能正常传递的func类型int。 错误的最后一部分我也不明白,expansion pattern ‘#‘nontype_argument_pack’ not supported by dump_expr#<expression error>’ contains no argument packs这可能是一个编译器错误(第82行是函数签名的主要部分,我在其中放置注释来标记它)?

奇怪的是,当我在调用submitAsync时删除显式模板参数时,替换此行:

return submitAsync<ReturnType, Args...>(function<ReturnType (Args...)>(func), forward<Args>(args)...);

用这个:

return submitAsync(function<ReturnType (Args...)>(func), forward<Args>(args)...);

GCC正确编译它。 那么,为什么GCC在指定模板参数时调用了错误的函数,即使它在允许推导出参数时工作正常呢?谁能告诉我第82行的奇怪错误是什么?

编辑:忘记提及,我正在使用GCC 4.7.2

编辑2:solution and explanation here

1 个答案:

答案 0 :(得分:1)

经过进一步测试,我意识到没有显式模板参数的Clang和GCC实际上并没有按照我的意愿工作。在这两种情况下,该函数只是将自身称为适合参数的第一个函数。这是由编译器决定submitAsync引起的,该函数将函数作为模板参数比采用const std::function&的函数更好。在更改submitAsync以通过引用获取函数后,它现在正常工作:

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