https://gcc.gnu.org/bugzilla/show_bug.cgi?id=81102
Bug ID: 81102 Summary: G++ wrong error report for partial template specialization Product: gcc Version: 7.1.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: boite.pour.spam at gmail dot com Target Milestone: --- Hi, This code used to work fine with G++ version < 7.0: template <int line, typename FuncSig, FuncSig f> struct HelperWrapper; // [...] // Zero-ary template <int line, typename Ret, Ret (&Func)()> struct HelperWrapper<line, Ret (&)(), Func> { static inline void* WrapFuncT(const int) { return (void*)Func; // Changed for the bug report, normally I capture the function pointer, and make a list of its arguments type here, and return an object that's callable and perform argument convertion via variant types. } }; // Unary template <int line, typename Ret, typename Arg1, Ret (&Func)(Arg1)> struct HelperWrapper<line, Ret (&)(Arg1), Func> { static inline void * WrapFuncT(const int) { return (void*)Func; // Changed } }; // Binary template <int line, typename Ret, typename Arg1, typename Arg2, Ret (&Func)(Arg1, Arg2)> struct HelperWrapper<line, Ret (&)(Arg1, Arg2), Func> { static inline void * WrapFuncT(const int) { return (void*)Func; // Changed } }; [...] Here's a godbolt that shows it starts failing since GCC v7.0.0 : godbolt.org/g/uW3D7O The diagnostic is: <source>:20:8: error: partial specialization 'struct HelperWrapper<line, Ret (&)(Arg1), Func>' is not more specialized than [-fpermissive] struct HelperWrapper<line, Ret (&)(Arg1), Func> ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ <source>:5:8: note: primary template 'template<int line, class FuncSig, FuncSig f> struct HelperWrapper' struct HelperWrapper; IIUC, in the zero-ary case, the primary template argument FuncSig (which should be matched to "Ret (&)()" does not match the specialized version "Ret" argument which only match the return type of the function argument. Thus, there does not exist any type that could lead to ambiguity here. For the other arity case, the diagnostic seems wrong too since there is an additional template argument for the function argument type. That is: it does not exist a type T that could match the specialized version while matching the primary template directly, since the type T must "embed" 2 different types: it's a function + a template argument type. Moreover, replacing the (&) part and (&Func) part by (*) and (*Func) makes G++ happy with the code. The C++ standard allows taking reference on function as it decays to function pointer, so the initial writing should be allowed without diagnostic. However this code is used on Microsoft C++ compiler too, and it only accept (&Func) version and fails compiling (*Func) version (this has been the case since 2007 IIRC). It's also accepted on Intel C++ compiler too, and on Clang (check the godbolt.org) Thus, since G++7.0, I have to make 2 version (one with function pointers and one with reference to support all compilers) and it's not very clean. It also fails on G++8.0 beta. Can you explain if it's a feature (and if yes, what is the reason for making a difference between function pointer and function reference, and the extract of the C++ standard that supports this claim) or a bug, please ? Thank you very much.