By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
424,953 Members | 1,131 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 424,953 IT Pros & Developers. It's quick & easy.

function template overloading

P: 14
Hi all,

i would appreciate help with the following problem: Please consider the code
Expand|Select|Wrap|Line Numbers
  1. #include <iostream>
  2. using namespace std;
  3.  
  4. template<typename T> struct A{};
  5. template<typename T> struct B: public A<T>{};
  6.  
  7. template<typename T> void f(T obj){ cout << "default\n"; }
  8. template<typename T> void f(A<T> obj){ cout << "special case\n"; }
  9.  
  10. int main(){
  11.     A<int> a;
  12.     f(a);
  13.     B<int> b;
  14.     f(b);
  15. }
  16.  
This code compiles fine and produces the output
Expand|Select|Wrap|Line Numbers
  1. special case
  2. default
As you can see - and I guess that is the way it is supposed to work - the special case implementation is only used if the template fits exactly, not by inheritance.

What I would like to do, however, is specify function f for the special case that it is called with parameter of type A<T> or B<T> for any type T and any child B of A.

Is there a way to do this? Or do I have to write another template (with the same code) for the case f(B<T> obj)?

Any advise appreciated, I can't think of a good way.

~<><~~~~~~ presencia
Sep 2 '10 #1
Share this Question
Share on Google+
6 Replies


weaknessforcats
Expert Mod 5K+
P: 9,197
You will need to make function f a memeber function for the special case.
Sep 2 '10 #2

P: 14
I am sorry I don't get it right away. What class should f be a member of?
Why exactly do I have to make it a member function?
And can I still call it the same way as the default version? (i.e., like: f(obj) )

Thanks for your time!
~<><~~~~~~~~ presencia
Sep 2 '10 #3

weaknessforcats
Expert Mod 5K+
P: 9,197
Is this what you had in mind? I'm not sure I have your program requirements correctly understood.

Expand|Select|Wrap|Line Numbers
  1. template<typename T> struct A
  2. {
  3.     virtual void f(A<T> obj){ cout << "special case\n"; } 
  4.  
  5. }; 
  6. template<typename T> struct B: public A<T>
  7. {
  8.     virtual void f(A<T> obj){ cout << "special case\n"; } 
  9.  
  10. }; 
  11.  
  12. template<typename T> void f(T obj){ cout << "default\n"; } 
  13.  
  14.  
  15. int main(){ 
  16.     A<int> a; 
  17.     a.f(a); 
  18.     B<int> b; 
  19.     b.f(b); 
  20.     f(a);
  21.     f(b);
Sep 5 '10 #4

P: 14
Thanks for your reply.
I am afraid, I didn't explain my problem well enough. So please let me try again:

I want to write a global function that does something. I want it to take one parameter of any type or class it can deal with. So I write a function template instead of a function, just like this:
Expand|Select|Wrap|Line Numbers
  1. //first function template f
  2. template<typename T> void f(T obj){ /*do something*/ }
Everything works well for now. I can call function f with just any object.

But now I have a class template A:
Expand|Select|Wrap|Line Numbers
  1. template<typename T> struct A{};
and I would like f to behave differently if the parameter provided is of type A<T> for any typename T. So I want to overload f, just like this:
Expand|Select|Wrap|Line Numbers
  1. //second function template f
  2. template<typename T> void f(A<T> obj){ /*do a different thing*/ }
Now, when I call f with an object of type A<T> like this
Expand|Select|Wrap|Line Numbers
  1. A<int> a;
  2. f(a);
the code of the second function template f is executed, just as I wanted. But I want this "second version of f" to be executed if called with a parameter of type B<T> for any child B of A and any typename T, just like this:
Expand|Select|Wrap|Line Numbers
  1. template<typename T> struct B: public A<T>{};
  2. B<int> b;
  3. f(b);
However, executing the last code will call the FIRST version of function template f.

Now, there is a simple solution for this: I can just copy the code of template<typename T> void f(A<T> obj) and write function templates template<typename T> void f(B<T> obj) for all children B of A, all with the exact same code to be executed.

My question is: I there a way to produce the function f like I want it without making a copy of the code for every class derived from A?

Thanks for considering my question.
~<><~~~~ presencia
Sep 6 '10 #5

weaknessforcats
Expert Mod 5K+
P: 9,197
Try:

Expand|Select|Wrap|Line Numbers
  1. template<typename T> struct A
  2. {
  3.  
  4.     virtual void f();
  5.  
  6. }; 
  7. template<class T>
  8. void A<T>::f()
  9. { cout << "A special case\n"; } 
  10.  
  11. template<typename T> struct B: public A<T>
  12. {   
  13.  
  14.     virtual void f(); 
  15.  
  16. };
  17. template<typename T>
  18. void B<T>::f(){ cout << "B special case\n"; } 
  19.  
  20. template<typename T> void f(T& obj){ cout << "default\n"; } 
  21. template<typename T> void f(A<T>* obj){ obj->f();}
  22.  
  23.  struct C
  24.  {
  25.  
  26.  };
  27. int main(){ 
  28.     A<int> a; 
  29.     B<int> b; 
  30.     f(&a);
  31.     f(&b);
  32.     C c;
  33.     f(c);
  34.  
The idea here is that when you call the global f using a pointer to get a virtual function call into the struct A hierarchy. That will call the correct f() for the child of A. When you call the global f() by reference, you get your default case.

Note the global f() overload uses a T& and an A<T>*.

You will not be able to overload the global f() using T and A<T>*. The pointer is seen as a T and you get the wrong template. However, a reference requires an object so the compiler sees A<T>* as a better fit than T& and picks the right template.

Does this work for you?
Sep 6 '10 #6

100+
P: 207
Even though this might not be an elegant solution to your problem you could always do this.

Expand|Select|Wrap|Line Numbers
  1. #include <iostream>
  2.  
  3. template<class T>
  4. struct A
  5. {
  6.  
  7. };
  8.  
  9. template<class T>
  10. struct B : public A<T>
  11. {
  12.  
  13. };
  14.  
  15. struct C
  16. {
  17.  
  18. };
  19.  
  20. template<typename T>
  21. void f( T & obj)
  22. {
  23.        std::cout << "default case" << std::endl;
  24. }
  25.  
  26. template<typename T>
  27. void f(A<T> & obj)
  28. {
  29.        std::cout << "special case" << std::endl;
  30. }
  31.  
  32. template<typename T>
  33. void f(B<T> & obj)
  34. {
  35.        A<T> * reference = dynamic_cast<A<T>*>(&obj);
  36.        if(reference != 0)
  37.        {
  38.               f(*reference);
  39.        }
  40. }
  41.  
  42. int main()
  43. {
  44.  
  45.        A<int> a;
  46.        B<int> b;
  47.        C c;
  48.  
  49.        f(a);
  50.        f(b);
  51.        f(c);
  52.  
  53.        return 0;
  54.  
  55. }
  56.  
The benefit here is that you can use don't have to remember to include the address of operator if you want to call the A<T> or B<T> template versions.
Sep 8 '10 #7

Post your reply

Sign in to post your reply or Sign up for a free account.