4

Got this code that used to compile fine with previous version of gcc:

template <int line, typename FuncSig, FuncSig f>
struct HelperWrapper;

// [...]

template <int line, typename Ret, Ret (&Func)()>
struct HelperWrapper<line, Ret (&)(), Func>
{
    static inline int WrapFuncT(const int)
    {
        return 0; // Changed
    }
};

// Unary
template <int line, typename Ret, typename Arg1, Ret (&Func)(Arg1)>
struct HelperWrapper<line, Ret (&)(Arg1), Func>
{
    static inline int WrapFuncT(const int)
    {
        return 1; // Changed
    }
};

// Binary
template <int line, typename Ret, typename Arg1, typename Arg2, Ret (&Func)(Arg1, Arg2)>
struct HelperWrapper<line, Ret (&)(Arg1, Arg2), Func>
{
    static inline int WrapFuncT(const int)
    {
        return 2; // Changed
    }
};

Is rejected by GCC 7.1.1 with error:

a.hpp:683:16: error: partial specialization 'struct Type::Implementation::HelperWrapper<line, Ret (&)(), Func>' is not more specialized than [-fpermissive]
     struct HelperWrapper<line, Ret (&)(void), Func>
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
a.hpp:640:16: note: primary template 'template<int line, class FuncSig, FuncSig f> struct Type::Implementation::HelperWrapper'
     struct HelperWrapper;
            ^~~~~~~~~~~~~
a.hpp:695:16: error: partial specialization 'struct Type::Implementation::HelperWrapper<line, Ret (&)(Arg1), Func>' is not more specialized than [-fpermissive]
     struct HelperWrapper<line, Ret (&)(Arg1), Func>
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
a.hpp:640:16: note: primary template 'template<int line, class FuncSig, FuncSig f> struct Type::Implementation::HelperWrapper'
     struct HelperWrapper;
            ^~~~~~~~~~~~~
a.hpp:707:16: error: partial specialization 'struct Type::Implementation::HelperWrapper<line, Ret (&)(Arg1, Arg2), Func>' is not more specialized than [-fpermissive]
     struct HelperWrapper<line, Ret (&)(Arg1, Arg2), Func>
            ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
a.hpp:640:16: note: primary template 'template<int line, class FuncSig, FuncSig f> struct Type::Implementation::HelperWrapper'
     struct HelperWrapper;

I don't understand the message, since what GCC says as the primary template is, as I understand it, a forward declaration of a generic template structure that does not exists anywhere in the code.

The idea of this code is to capture the signature and the argument type of the function passed in.

1) Is GCC right ? (If you think it's not, please cite what supports your claim in the current standard)

2) How do I fix the code so it's accepted by GCC (it's accepted with Clang down to VisualStudio 2003). I can not use C++11.

Edit: I finally succeed reporting this to GCC developers and it's a bug that should be fixed in next versions.

xryl669
  • 3,376
  • 24
  • 47
  • 2
    The title mentions a *function template* yet the code contains only a class template? And you cannot use C++11? Then use gcc 4.4! – Walter Jun 09 '17 at 15:38
  • @Walter, Thanks, I've fixed the title. The code is cross platform and must compile on old system. It uses to compile fine with all compilers I've tested so far, except the recent GCC7.1 – xryl669 Jun 09 '17 at 15:45
  • Do you tell g++ *not* to compile with C++11 (or later) as target? AFAIK this is now the default, so you need to pass `-std=c++03` or whatever ancient standard you're targeting to g++ – Daniel Jour Jun 09 '17 at 18:01
  • Tried it, does not make a difference. Here's a godbolt showing it only fails with GCC 7.1 (all other compiler accept this) https://godbolt.org/g/uW3D7O – xryl669 Jun 09 '17 at 18:10
  • C++14 (no idea which compiler or version) works http://ideone.com/PHuA5p so possibly a bug. I'd post it to their bug tracker – Daniel Jour Jun 09 '17 at 18:18
  • I'm not able to sign up on gcc bug tracker. Seems like it's closed. – xryl669 Jun 11 '17 at 21:12
  • Have you tried changing from function references to function pointers? just for curiousity... (sorry I don't have a gcc compiler so I can't test it) – Mango Jun 12 '17 at 09:34

1 Answers1

1

It seems like a compiler bug but haven't found any reference to this problem on GCC Bugzilla. Nonetheless I tested your code with the recent GCC compilers on Compiler Explorer as you did and using function pointers instead of function references works with GCC 7.1 too. Here is a live demo.


The compiler might complain if the partial template specialization is not more specialized than the primary template. But in this case GCC is wrong because you specialized the FuncSig template parameter as a function reference (Ret (&)()). The more strange fact is that the compiler doesn't complain for function pointers.

Moreover the cause of the problem seems that not the FuncSig but the f template parameter. When I removed the f from primary template and from its specializations the problem disappeared:

template <int line, typename FuncSig>
struct HelperWrapper;

template <int line, typename Ret>
struct HelperWrapper<line, Ret (&)()> {
    static inline int WrapFuncT(const int) {
        return 0;
    }
};

/* ... */

See the live demo here.

Akira
  • 4,385
  • 3
  • 24
  • 46
  • Are you able to report a bug on GCC bugzilla ? I fail to register an account there (maybe you have one already). – xryl669 Jun 12 '17 at 13:21
  • The code I'm using is more complex than this snippet (the WrapFunc in fact captures the types of arguments and the return type so it can be transformed later on from different value type). But since your answer does fix the compilation for the presented snippet, I'm going to accept it. Unfortunately using function pointers instead of reference does not work on Microsoft Visual Studio compilers. So in the end, I'll do a `#if (__GNUC__ >= 7)` to change the parameter type based on the compiler. Thanks – xryl669 Jun 12 '17 at 13:26
  • You've answered 2), can you answer 1) ? – xryl669 Jun 12 '17 at 13:32
  • Unfortunately I have no GCC Bugzilla account so I can't report this bug. And it is still exists in the experimental 8.0.0 version too. – Akira Jun 12 '17 at 16:28