Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

g++ Bug with Partial Template Specialization

I am writing some TMP-heavy code for g++ (version 4.8.1_1, Macports) and clang++ (version 3.3, Macports). While g++ rejects the following code listing with UNBRIDLED FURY, clang++ compiles it with grace and splendor.

  • Which complier is in the right? (I strongly suspect it's g++, but I want to get some reassurance from others before submitting a bug report.)
  • Do you have any easy or elegant workarounds to suggest? (I need to use template aliases, so switching over to structs, which causes g++ to accept the code, is not an option.)

Here is the code listing, made just for you.

template <class... Ts>
struct sequence;

template <int T>
struct integer;

// This definition of `extents` causes g++ to issue a compile-time error.
template <int... Ts>
using extents = sequence<integer<Ts>...>;

// However, this definition works without any problems.
// template <int... Ts>
// struct extents;

template <int A, int B, class Current>
struct foo;

template <int A, int B, int... Ts>
struct foo<A, B, extents<Ts...>>
{
    using type = int;
};

template <int B, int... Ts>
struct foo<B, B, extents<Ts...>>
{
    using type = int;
};

int main()
{
    using t = foo<1, 1, extents<>>::type;
    return 0;
}

Here is g++'s output:

er.cpp: In function 'int main()':
er.cpp:39:41: error: ambiguous class template instantiation for 'struct foo<1, 1, sequence<> >'
  using t = typename foo<1, 1, extents<>>::type;
                                         ^
er.cpp:26:8: error: candidates are: struct foo<A, B, sequence<integer<Ts>...> >
 struct foo<A, B, extents<Ts...>>
        ^
er.cpp:32:8: error:                 struct foo<B, B, sequence<integer<Ts>...> >
 struct foo<B, B, extents<Ts...>>
        ^
er.cpp:39:43: error: 'type' in 'struct foo<1, 1, sequence<> >' does not name a type
  using t = typename foo<1, 1, extents<>>::type;
                                           ^

Here is clang++'s output:

Thanks for your help!

like image 377
void-pointer Avatar asked Jul 17 '13 12:07

void-pointer


Video Answer


1 Answers

This seems like a g++ bug because clearly foo<B, B, extents> is more specialized than foo<A, B, extents> (te latter can match anything that the former matches, but not vice versa), so the compiler should choose that specialization.

As you noted yourself, changing extents from a template alias to a class template, solves the problem.

like image 51
TemplateRex Avatar answered Oct 18 '22 22:10

TemplateRex