13

I have found this piece of bogus code (contrived example below):

template <int I, typename T>
struct foo
{
    static int bar()
    {
        return 1;
    }
};

template <std::size_t Index, typename T>
struct foo<Index, T*>
{
    static int bar()
    {
        return 2;
    }
};

Please note that specialization uses different type (by mistake). Surprisingly it compiles without any errors (or warnings) with both GCC 4.8.1 and Clang 3.4. But what is even more strange for GCC line foo<0, int*>::bar() results in 1, but Clang gives 2. What is going on? Is it still considered as a specialization by the standard?

magor
  • 359
  • 1
  • 11

2 Answers2

2

Gcc is wrong, because you simply can't call this specialization. Just remove primary template definition:

template <int I, typename T>
struct foo;

template <std::size_t Index>
struct foo<Index, int*> {
  static int bar() {
    return 2;
  }
};

int main() {
  std::cout << foo<std::size_t(0), int*>::bar() << std::endl; // nope, not work
  std::cout << foo<0, int*>::bar() << std::endl; // nope, not work
}

See live example. And this code must report ambiguous partial specialization, but it's not (for gcc). Clang report "ambiguous".

PS I argee, that this part is not covered enough by standard.

update

clang in this situation won't work with enums, example.

  • I am almost positive that it is a GCC bug, I will fill a bug report later on. Meanwhile I think I should accept your answer :-) And I will keep you posted – magor Sep 18 '13 at 10:19
0

The restrictions on partially specializing a class template on a non-type template argument 14.5.5 [temp.class.spec] paragraph 8 list the following restriction:

A partially specialized non-type argument expression shall not involve a template parameter of the partial specialization except when the argument expression is a simple identifier.

The argument expression using a size_t involves a conversion to int (size_t is unsigned) and is, thus, not a simple identifier.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380
  • @ruslo: It sure looks like a simple identifier but actually is `int(Index)` which doesn't seem to be a simple identifier anymore. – Dietmar Kühl Sep 17 '13 at 18:39
  • @ruslo: that maybe true for the identifier but the restriction clearly talks about the expression and that has to become `int(Index)` as the type of the entity identified by the identifier is `std::size_t` which is guaranteed not to be `int`. – Dietmar Kühl Sep 17 '13 at 19:01