1

I can find plenty of help with partial specialisation of templated classes, but I want to partially specialise a method of a non-templated class.

class TempMembMeth {
  public:
    template<typename T1, typename T2>
    void templMethod1(int);
};

My templated method implementation:

template<typename T1, typename T2>
  void TempMembMeth::templMethod1(int){
  std::cout << "<T1,T2>templMethod1(int)" << '\n';
}

I can fully spec the method OK:

template<>
inline void TempMembMeth::templMethod1<char,char>(int){
    std::cout << "<char,char>templMethod1(int)" << '\n';
}

But how can I do a partial specification?

template<typename T2>
inline void TempMembMeth::templMethod1<char,T2>(int){
    std::cout << "<char,?>templMethod1(int)" << '\n';
}

I get: 'TempMembMeth::templMethod1' : illegal use of explicit template arguments I can't re-define the class with the partially specialised method, since the class is not templated. Neither will it let me "overload" the templated method within the class - again it complains of illegal use of explicit template arguments.

So any ideas if this is possible? For the moment I have worked arround it by templating the class, but I wondered if this were possible without a templated class.

StephenD
  • 231
  • 1
  • 10
  • 2
    You can't partially specialize function templates. – T.C. Aug 29 '14 at 15:46
  • possible duplicate of [Why function template cannot be partially specialized?](http://stackoverflow.com/questions/5101516/why-function-template-cannot-be-partially-specialized) – IdeaHat Aug 29 '14 at 15:48
  • 1
    You may forward the implementation to a template (helper) class instead of template the whole class. – Jarod42 Aug 29 '14 at 15:56
  • If you want the type names and that is all, try using `typeid(T1).name()` and `typeid(T2).name()`. But they will be mangled by the compiler... probably. Ah, the great non-standardization of standard-library features. – RamblingMad Aug 29 '14 at 16:01

2 Answers2

1

As TC commented, you can't partially specialize template functions.

You should use overloading instead. If necessary, you can add some private functions with a Type2Type parameter. Something like:

#include <iostream>

struct Test
{
public:

    template<typename T1, typename T2>
    void templMethod1(int i)
    {
        templMethodImpl(i, Type2Type<T1>(), Type2Type<T2>());
    }

private:

    template<typename T>
    struct Type2Type
    {
        typedef T OriginalType;
    };

    template<class T1, class T2>
    void templMethodImpl(int i, Type2Type<T1>, Type2Type<T2>)
    {
        std::cout << "t1 any, t2 any" << std::endl;
    }

    template<class T2>
    void templMethodImpl(int i, Type2Type<char>, Type2Type<T2>)
    { 
        std::cout << "t1 char, t2 any" << std::endl;
    }

    void templMethodImpl(int i, Type2Type<int>, Type2Type<char>)
    {
        std::cout << "t1 int, t2 char" << std::endl;
    }
};

int main()
{
    Test test;

    test.templMethod1<char, char>(5);
    test.templMethod1<int, char>(5);
    test.templMethod1<char, int>(5);
    test.templMethod1<int, int>(5);
}
user673679
  • 1,327
  • 1
  • 16
  • 35
  • Thanks. A neat way to produce dummy type arguments. The Type2Type struct can be left empty. I presume that function calls would involve the compiler pushing the dummy type arguments onto the stack. Or would the optimizer omit them as anonymous arguments? – StephenD Aug 30 '14 at 18:05
1

As others have already noted, you cannot partially specialize function templates. However, you can use a helper class with almost equal effect.

#include <iostream>

namespace details
{
   // Forward declaration of the helper class.
   template<typename T1, typename T2> struct Helper;
}

class TempMembMeth 
{
  public:

    template<typename T1, typename T2>
    void templMethod1(int arg)
    {
       details::Helper<T1, T2>::doit(this, arg);
    }
};

namespace details
{
   // Implement the helper class and its specializations.
   template<typename T1, typename T2> struct Helper
   {
      static void doit(TempMembMeth* obj, int arg)
      {
         std::cout << "In Helper<T1,T2>::doit()\n";
      }
   };

   template<typename T2> struct Helper<char, T2>
   {
      static void doit(TempMembMeth* obj, int arg)
      {
         std::cout << "In Helper<char,T2>::doit()\n";
      }
   };

   template<> struct Helper<char, char>
   {
      static void doit(TempMembMeth* obj, int arg)
      {
         std::cout << "In Helper<char, char>::doit()\n";
      }
   };
}

int main()
{
   TempMembMeth obj;
   obj.templMethod1<float, int>(10);
   obj.templMethod1<char, double>(20);
   obj.templMethod1<char, char>(30);
   return 0;
}

Output:

In Helper<T1,T2>::doit()
In Helper<char,T2>::doit()
In Helper<char, char>::doit()
T.C.
  • 133,968
  • 17
  • 288
  • 421
R Sahu
  • 204,454
  • 14
  • 159
  • 270
  • This seems like a very clean solution. The details namespace can be left anonymous to simplify it a little. Also in practice, the helper class would probably need to be made a friend of the TempMembMeth class. – StephenD Aug 30 '14 at 18:08