Question

I'm trying to specialize a template member function of a non-template class using a templatized parameter:

#include <array>
class C
{
public:
  template<class Container>
  void Foo( Container& )
  {
    // ...
  }
};

template<class T, std::size_t N>
template<>
void C::Foo< std::tr1::array<T,N> >( std::tr1::array<T,N>& )
{
  // special
}

I get an error "illegal use of explicit template arguments" with this. What's the right syntax to make this valid?


Update:

Perhaps I've muddled the issue by over-simplifying. What I really want to do is specially handle this one case where there is a dependent name involved, which I think may be what is throwing a monkey wrench into the works here. My original thought was to overload the function as such:

class C
{
public:
  template<class Iter>
  void Foo( Iter )
  {
    std::cout << "Normal\n";
  }

  template<class T, std::size_t N>
  void Foo( typename std::tr1::array<T,N>::iterator )
  {
    std::cout << "Special\n";
  }
};

int main()
{
  C c;
  std::tr1::array<int,10> a1;
  c.Foo( a1.begin() ); // Doesn't print "Special"!
}

But the special Foo doesn't get called. How can I do that?

Was it helpful?

Solution

Only the member function is templated, which means that you should only use one template<...> in there. But that will not solve it either, as you cannot partially specialize a function.

The usual way of handling the problem is through overloads, rather than specialization (specialization of template functions is not that useful).

struct test {
   template <typename Container>
   void f( Container& ) { ... }

   template <typename T, int N>
   void f( std::array<T,N>& ) { ... }
};

Note that the difference is that they are two separate template functions (rather than an specialization).

EDIT: After the update

The update to the question changes the problem completely. The problem that you are seeing is that the argument of the second version is a dependent name, and as such it is non deducible. Given the function call the compiler is not able to determine what type T, and integral constant N are to match that particular instantiation. Consider a different example:

template <typename T>
struct inner_int {
   typedef int type;
};
template <typename T>
void foo( typename inner_int<T>::type ) {
}
int main() {
   foo( inner_int<double>::type() );
}

When the compiler processes the call in main, it instantiates the template and extracts the type, from that it creates a temporary, and then it tries to decide what to do with foo but at that time it only knows that it is being called with an int rvalue... the original inner<double>::type is gone, now it is just foo( int() ) and the compiler would have to try and instantiate inner_int with all possible types to determine whether any of them fits, and in the worse case, as above, many would match.

OTHER TIPS

Partial function template specialization is illegal. From the C++03 standard, §14/2:

A template-declaration can appear only as a namespace scope or class scope declaration. In a function template declaration, the declarator-id shall be a template-name (i.e., not a template-id). [Note: in a class template declaration, if the class name is a template-id, the declaration declares a class template partial specialization.]

You'll want to simply overload your function instead:

class C
{
public:
    template<typename Container>
    void Foo(Container&)
    {
        // ...
    }

    template<typename T, std::size_t N>
    void Foo(std::tr1::array<T, N>&)
    {
        // special
    }
};

EDIT (in response to the OP's edit):

If you're only looking for a workaround for this specific scenario, since std(::tr1)::array<T,N>::iterator is simply T*, your 'special' overload can be:

template<typename T>
void Foo(T*&)
{
    // special
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top