14

Why does the following compile with clang but not with g++ 4.9

#include <array>

template< typename T1, typename T2 , typename T3 = int>
struct A;

template<typename T, unsigned int N, typename T2, typename T3>
struct A< std::array<T,N>, T2,  T3 > {
    int a;
};

int main()
{
  A< std::array<int,10>, double>  a;
  a.a +=3;
}

http://coliru.stacked-crooked.com/a/c7800f49ba5aac43

g++ does not find a suitable specialization and complains with "incomplete type". I am wondering since, the default argument typename T3 = int should apply for the specialization (or does it only apply for full specialization?)

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
Gabriel
  • 8,990
  • 6
  • 57
  • 101

1 Answers1

4

The templates A<T1, T2, T3> and A<T1, T2> are not complete defined so you can't use your members, you can solve the problem defining this templates at this way:

#include <array>

template< typename T1, typename T2 , typename T3 = int>
struct A {
    int a;
};

template<typename T, unsigned int N, typename T2, typename T3>
struct A< std::array<T,N>, T2,  T3 > {
    int a;
};

int main()
{
    A< std::array<int,10>, double>  a;
    a.a +=3;
}

Another fine example of specialization more simple:

template<typename T, unsigned int N>
struct A {
    T a = N;
};

template<unsigned int N>
struct A<int, N> {
    int a = 2*N;
};

#include <iostream>
using namespace std;

main() {
    A<float, 30> af;
    A<int, 30> ai;
    cout << af.a << endl << ai.a << endl;
}

Like @dys say's on your comment using std::size_t instead unsigned int works:

template< typename T1, typename T2 , typename T3 = int>
struct A;

template<typename T, std::size_t N, typename T2, typename T3>
struct A< std::array<T,N>, T2,  T3 > { 
        T3 a = N;
        int b; 
};

int main()
{
        A< std::array<int,10>, double>  a;
        a.a +=3;

        A< std::array<int,10>, double, int>  b;
        b.b +=3;
}
David Kennedy
  • 370
  • 2
  • 12
  • 1
    I dont think thats the answer, the asnwer should be @dyp's comment. The problem is that it matches the first prototype (which is incomplete yes) because the template matching is obviously pedantic about the used types -> ``template std::array`` – Gabriel Oct 19 '15 at 16:29
  • @dyp are really right, using `std::size_t` instead `unsigned int` works fine. – David Kennedy Oct 23 '15 at 13:12