43

What is the C++ syntax for specializing a template function that's inside a template class? For example, consider that I have the following two classes and their usage. I would like to be able to provide specialized implementations of the method X::getAThing() for different types. E.g.: int, std::string, arbitrary pointer or class, etc.

template <class c1> class X {
public:
   template<typename returnT> returnT getAThing(std::string param);
   static std::string getName();
private:
   c1 theData;
};

// This works ok...
template <class c1> std::string X<c1>::getName() {
   return c1::getName();
}

// This blows up with the error:
// error: prototype for 'int X<c1>::getAThing(std::string)' does not match any in class 'X<c1>'
template <class c1> template <typename returnT> int X<c1>::getAThing(std::string param) {
   return getIntThing(param); // Some function that crunches on param and returns an int.
}

// More specialized definitions of getAThing() for other types/classes go here...

class Y {
public:
   static std::string getName() { return "Y"; }
};

int main(int argc, char* argv[])
{
   X<Y> tester;
   int anIntThing = tester.getAThing<int>(std::string("param"));
   cout << "Name: " <<  tester.getName() << endl;
   cout << "An int thing: " << anIntThing << endl;
}

I've been trying to guess at the correct syntax for the specialization for at least an hour, and can't figure anything out that will compile. Any help would be greatly appreciated!

Ogre Psalm33
  • 21,366
  • 16
  • 74
  • 92

6 Answers6

24

AFAIK (and the standards experts can correct me), you cannot specialize a templated function of a class template without specializing the class itself...

i.e. the following I think will work:

template <> template <> int X<Y>::getAThing<int>(std::string param) {
   return getIntThing(param); // Some function that crunches on param and returns an int.
}
Nim
  • 33,299
  • 2
  • 62
  • 101
  • The error messages I'm getting from gcc indicate that you are likely correct. Though it's difficult to say since templates often lead to strange and inscrutable error messages. And actually testing that in gcc does, in fact, work. I would say that you're right, even though finding exactly where the standard says that is an interesting business. – Omnifarious Feb 14 '11 at 17:24
  • 2
    @Omnifarious, I know what you mean, I was stumped by this for about an hour today: `expected primary-expression before ‘>’`!?! turns out I was missing the key word `template` in a call to a function template within a class template, now uses odd syntax: `some_obj.template foo();` - wtf? who thought that was a clever idea?!? – Nim Feb 14 '11 at 17:28
  • Ick, that's what I was afraid of. – Ogre Psalm33 Feb 14 '11 at 17:31
  • 2
    @Omnifarious: 14.7.3p18: "In an explicit specialization declaration for a member of a class template or a member template that appears in namespace scope, the member template and some of its enclosing class templates may remain unspecialized, except that the declaration shall not explicitly specialize a class member template if its enclosing class templates are not explicitly specialized as well." – aschepler Feb 14 '11 at 18:09
  • 2
    I think I have a good grasp of English, but it's statements like that, that make my eyes run, the reason that I've avoided reading the standards... – Nim Feb 14 '11 at 20:16
10

C++ has no concept of partial specialization for function templates. However, you can get the same effect as full specialization through function overloading.

I am assuming you have something like this, which is really one of the only ways to do it.

template<class TYPE>
class MyInterface {
public:
    template<class RETURN>
    RETURN myFunction(RETURN& ref, ....);
};

In this case, you specialize "myFunction()" by declaring ordinary member functions with the desired type. C++'s function overloading rules should give you what you want, e.g.

template<class TYPE>
class MyInterface {
public:
    template<class RETURN>
    RETURN myFunction(RETURN& ref, ....);

    // String specialization
    std::string myFunction(std::string& ref, ...);
};

The compiler will use the "std::string" function where appropriate, and may never use the inner template at all.

Zack Yezek
  • 201
  • 3
  • 2
7

So, I'm taking a different approach to answering your question. I'm going to start from something that sort of does what you want, and works. And then maybe we can figure out how to permute it into something closer to what you really want:

#include <string>
#include <iostream>

int getIntThing(const ::std::string &param);

template <typename returnT>
returnT getThingFree(const ::std::string &param);

template <>
int getThingFree<int>(const ::std::string &param)
{
   return getIntThing(param);
}

// More specialized definitions of getAThing() for other types/classes
// go here...

template <class c1> class X {
public:
   template<typename returnT> returnT getAThing(std::string param);
   static std::string getName();
private:
   c1 theData;
};

// This works ok...
template <class c1> std::string X<c1>::getName() {
   return c1::getName();
}

// This also works, but it would be nice if I could explicitly specialize
// this instead of having to explicitly specialize getThingFree.
template <class c1>
template <class RT>
RT X<c1>::getAThing(std::string param) {
   // Some function that crunches on param and returns an RT.
   // Gosh, wouldn't it be nice if I didn't have to redirect through
   // this free function?
   return getThingFree<RT>(param);
}

class Y {
public:
   static std::string getName() { return "Y"; }
};

int main(int argc, char* argv[])
{
   using ::std::cout;
   X<Y> tester;
   int anIntThing = tester.getAThing<int>(std::string("param"));
   cout << "Name: " <<  tester.getName() << '\n';
   cout << "An int thing: " << anIntThing << '\n';
}

Here is another idea that sort of works, and isn't exactly what you want, but is closer. I think you've thought of it yourself. It's also rather ugly in the way it uses type deduction.

#include <string>
#include <iostream>

template <class c1> class X;

int getIntThing(const ::std::string &param)
{
   return param.size();
}

// You can partially specialize this, but only for the class, or the
// class and return type. You cannot partially specialize this for
// just the return type. OTOH, specializations will be able to access
// private or protected members of X<c1> as this class is declared a
// friend.
template <class c1>
class friendlyGetThing {
 public:
   template <typename return_t>
   static return_t getThing(X<c1> &xthis, const ::std::string &param,
                            return_t *);
};

// This can be partially specialized on either class, return type, or
// both, but it cannot be declared a friend, so will have no access to
// private or protected members of X<c1>.
template <class c1, typename return_t>
class getThingFunctor {
 public:
   typedef return_t r_t;

   return_t operator()(X<c1> &xthis, const ::std::string &param) {
      return_t *fred = 0;
      return friendlyGetThing<c1>::getThing(xthis, param, fred);
   }
};

template <class c1> class X {
public:
   friend class friendlyGetThing<c1>;

   template<typename returnT> returnT getAThing(std::string param) {
      return getThingFunctor<c1, returnT>()(*this, param);
   }
   static std::string getName();
private:
   c1 theData;
};

// This works ok...
template <class c1> std::string X<c1>::getName() {
   return c1::getName();
}

class Y {
public:
   static std::string getName() { return "Y"; }
};

template <class c1>
class getThingFunctor<c1, int> {
 public:
   int operator()(X<c1> &xthis, const ::std::string &param) {
      return getIntThing(param);
   }
};

// More specialized definitions of getAThingFunctor for other types/classes
// go here...

int main(int argc, char* argv[])
{
   using ::std::cout;
   X<Y> tester;
   int anIntThing = tester.getAThing<int>(std::string("param"));
   cout << "Name: " <<  tester.getName() << '\n';
   cout << "An int thing: " << anIntThing << '\n';
}

I would recommend declaring getThingFunctor and friendlyGetThing in a semi-private utility namespace.

Omnifarious
  • 54,333
  • 19
  • 131
  • 194
  • This is probably the only approach with any chance of success. I tried with a nested helper class, since rules for class specialization are different from functions, but no joy. Nit: Shouldn't that last comment be "More specialized definitions of **getThingFree**", and also they have to go above? – Ben Voigt Feb 14 '11 at 17:25
  • @Ben Voigt - Your nit is noted and taken care of. :-) – Omnifarious Feb 14 '11 at 17:34
  • Wow, I was hoping the language wouldn't force me to do something so icky. As I mentioned elsewhere, it'd be nice to not have to specialize every combination of class c1 and returnT. – Ogre Psalm33 Feb 14 '11 at 17:43
  • @Ogre Psalm33 - So, will any implementation of getAThing need access to the private parts of `class X`? – Omnifarious Feb 14 '11 at 17:53
  • @Omnifarious - well, looking at my "real" implementation, it's currently accessing protected members, but I'm thinking I could wiggle the implementation and take out the dependency on protected members as well. – Ogre Psalm33 Feb 14 '11 at 18:21
  • Ok, that's downright ugly and horrible looking (speaking of the C++ syntax gymnastics required, not your code :-), but I think I can use a slight variation on your functor solution to get what I want. Thanks! – Ogre Psalm33 Feb 14 '11 at 18:49
  • @Ogre Psalm33 - I agree, the gymnastics required are pretty ugly. I find the set of restrictions on what is and isn't allowed to be a little odd. They don't seem to have any rhyme or reason that I can detect. – Omnifarious Feb 14 '11 at 18:53
1

For the curious, this is probably the solution I'm going to go with in my own code. This is a slight variation on Omnifarious's answer, that eliminates the need for an extra class. I still give props to Omnifarious, as he did most of the leg work:

#include <iostream>
#include <string>

using namespace std;

// IMPORTANT NOTE: AdaptingFunctor has no access to the guts of class X!
// Thus, this solution is somewhat limited.
template<typename t1> class AdaptingFunctor {
public:
   t1 operator() (string param);
};

// Can specialize AdaptingFunctor for each type required:
template<> int AdaptingFunctor<int>::operator() (string param)
{
   return param.size(); // <=== Insert required type-specific logic here
}

// Additional specializations for each return type can go
// here, without requiring specialization of class c1 for X...


template <class c1> class X {
public:
   template<typename returnT>  returnT getAThing(std::string param)
      {
     AdaptingFunctor<returnT> adapter;
     return adapter(param);
      }
   static std::string getName();
private:
   c1 theData;
};

// Template definition of class method works ok...
template <class c1> std::string X<c1>::getName() {
   return c1::getName();
}

class Y {
public:
   static std::string getName() { return "Y"; }
};


int main(int argc, char* argv[])
{
   X<Y> tester;
   int anIntThing = tester.getAThing<int>(std::string("param"));
   cout << "Name: " <<  tester.getName() << endl;
   cout << "An int thing: " << anIntThing << endl;
}
Community
  • 1
  • 1
Ogre Psalm33
  • 21,366
  • 16
  • 74
  • 92
-1

Here's the simplest, easiest way I've seen so far to do this:

template <class T1>
struct MyClass {
  template <class T2>
  void MyFunction();
};

template <class T1>
template <class T2>
void MyClass<T1>::MyFunction() {  // NOTE:  NO T2 on this line.
  // Code goes here
}
user524177
  • 37
  • 1
  • 1
    The OP wants each 'T2' to use a different function body (in the syntactic sense). Your example uses the same function body for all kinds of T2. – Richard Corden May 04 '11 at 17:41
  • Richard Corden is correct. We wanted to be able to specialize MyFunction's body for many different classes or types, where (and this is the important part) T2 can be any basic type. – Ogre Psalm33 May 04 '11 at 22:00
-2

Try

template <>
template <class T>
int X<T>::template getAThing<int>(std::string param)
{
   return getIntThing(param);
}

This still doesn't compile, but it's closer than you had.

I think you can't specialize members en masse. You have to specify a particular specialization of the class template before you can start specializing its members.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • What if you reverse the order of the template brackets? ie `template template<>` instead. Makes more sense, since the template function is inside the template class, so it's template declaration should be nested within that of the class. Worth a try. – Alexander Kondratskiy Feb 14 '11 at 17:11
  • @Alexander Kondratskiy - I tried that. Still doesn't work. Much different error though. :-) – Omnifarious Feb 14 '11 at 17:13
  • Hmmm, interesting thoughts. Yeah, if I have to specialize the function for both (for example) class Y and int, that leaves me with a lot of potential combinations of functions to define. If your hunch is right Ben, I may have to drop back to doing something like implementing getAThing() using an external functor class, and specialize that, for cases where getAThing()'s definition does not depend on info from class c1. – Ogre Psalm33 Feb 14 '11 at 17:29
  • This doesn't make any sense. 'X' is being specialized with 'T' a nested template parameter. The type 'X' is unrelated to the original primary template and has no definition and no members. As 'getAThing' is not a member of that class you cannot specialize it in that class. – Richard Corden May 04 '11 at 17:34
  • @Richard: You're wrong about `X` being an empty specialization. The reason this fails is that you have to first specialize the class before specializing a member, and this doesn't. But since you insist on downvoting, feel free. – Ben Voigt May 05 '11 at 03:18
  • @Ben: I down voted because aside from the fact your example is illegal too, I don't think it is helpful. On the other point, you're right - I was wrong to say that 'X' is an empty specialization. After thinking about it a bit more - 'X' is simply not a sensible construct and so really has no meaning at all. – Richard Corden May 05 '11 at 13:02
  • @Richard: You might look at any example of out-of-class implementation of members of a template class, which is perfectly legal, and uses `template ` ... `X::` in just such a way. That's not the issue here. The problem with the OP's design is that C++ requires specializing the class before specializing members, if that requirement didn't exist, this would be the correct syntax. – Ben Voigt May 05 '11 at 13:29
  • @Ben: I understand the problem the OP has. Regarding your comment on out-of-class members, when you use 'T' where 'T' is a nested template parameter with a deeper nesting than the template your specializing then it's a different thing. TBH - I think we can just agree to differ. – Richard Corden May 05 '11 at 13:41