11

Say I have a templated class:

template <typename T>
class foo {
  void do_someting(T obj) {
    // do something generic...
  }
};

and I want to specialize do_something, but within it I want to call the "normal" do_something function:

template<>
void foo<MyObj>::do_something(MyObj obj) {
  // do something specific...
  // and ALSO do something generic!
}

is there a way to refer to the normal version of do_something within my specialized function? Or do I just have to copy the code?

(I know that I could refactor foo in such a way that I wouldn't have this exact problem, but as it happens I can't really modify the "real" foo, as it's heavily-shared code.)

Jacob B
  • 2,005
  • 13
  • 12
  • 4
    There is no "normal" version of `do_something` for the type `MyObj` - the entire effect of template specialization is to *replace* the instantiation that you would have got from the base template, with the class/function you define in the specialization. – Steve Jessop Nov 04 '10 at 17:11
  • possible duplicate of [How can I get a specialized template to use the unspecialized version of a member function?](http://stackoverflow.com/questions/347096/how-can-i-get-a-specialized-template-to-use-the-unspecialized-version-of-a-member) – Steve Townsend Nov 04 '10 at 17:12
  • 1
    Right, but the compiler knows about the code in foo::do_something, there's no reason why it couldn't let me refer to it somehow. I'm totally willing to believe that this language feature just doesn't exist, though---that's what I'm trying to find out. – Jacob B Nov 04 '10 at 17:13
  • 1
    @Steve Townsend -- that's a different question. That is asking how you can have a class with some specialized functions and some unspecialized functions. – Jacob B Nov 04 '10 at 17:15
  • "there's no reason why it couldn't let me refer to it somehow" - if templates were defined in a radically different way, there'd be no reason. As it is, `foo` is a class, and it has a `do_something` function, and that function is defined by the specialization. If the base template `foo` were instantiated with parameter `MyObj`, the result would be *another* class, also `foo`, which isn't allowed, and that's the obstacle. I guess if the language somehow let you instantiate the base template to a different name, you might be OK, but no such luck. – Steve Jessop Nov 04 '10 at 18:00

3 Answers3

7

No. Your specialization is the only definition that will exist for the MyObj type argument. But, consider modifying the foo template in this manner, which will be transparent to the current users of the template:

template<typename T>
class foo {
  void prelude(T &obj){ // choose a better name
    /* do nothing */
  }
  void do_something(T obj){
    prelude(obj);
    // do something generic...
  }
};

Then define a specialization for the prelude:

template<>
void foo<MyObj>::prelude(MyObj &obj){
  // do something specific
}

This is somewhat similar in structure to the main use case for private virtual members. (Sort of. Not really. But it's what inspired me in this answer.)

Steve M
  • 8,246
  • 2
  • 25
  • 26
1

You might also consider a type that is not MyObj, but implicitly converts to it, but the best way would be to refactor and perhaps extract the common generic something.

#include <iostream>
#include <boost/ref.hpp>
typedef int MyObj;


template <typename T>
struct foo {
  void do_something(T obj) {
    // do something generic...
    std::cout << "generic " << obj << '\n';
  }
};

template<>
void foo<MyObj>::do_something(MyObj obj) {
  // do something specific...
  std::cout << "special " << obj << '\n';
  // and ALSO do something generic!
  foo<boost::reference_wrapper<MyObj> >().do_something(boost::ref(obj));
}

int main()
{
    foo<int> f;
    f.do_something(10);
}
UncleBens
  • 40,819
  • 6
  • 57
  • 90
0

Yes, this this is actually quite straightforward. You just let the main, generic version of your function serve as a pass-through to an 'implementation' generic function which doesn't get partially specialized, then you can just call that from the specialized version of the initial function as needed.

template <typename T>
class foo 
{
  void do_something(T obj) 
  {
     do_something_impl(obj);
  }

  void do_something_impl(T obj)
  {
    // do something generic...
  }
};

Now the specialization can call the generic version without a problem:

template<>
void foo<MyObj>::do_something(MyObj obj) 
{
  // do something specific...
  do_something_impl(obj); //The generic part
}

I think this closer to your original intentions than Steve M.'s answer, and is what I do when faced with this issue.

Matt Phillips
  • 9,465
  • 8
  • 44
  • 75