Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overriding a function only for certain types in template

I have a base class with a virtual function:

class Base
{
public:
  virtual void Function();
};

void Base::Function()
{
  cout << "default version" << endl;
}

and a derived template class:

template <class T> class Derived : public Base
{
public:
  virtual void Function();
};

Is there a way to make Function() be taken from the base class for all types, except some chosen ones? So what I want is to be able to define an overriden Function() for, say, int and long:

void Derived<int>::Function()
{
  cout << "overriden version 1" << endl;
}

void Derived<long>::Function()
{
  cout << "overriden version 2" << endl;
}

and to have the default version of Function() for all other types, without explicit definition of Function() for them, so the output of

int main ()
{
  Derived<int> derivedInt;
  derivedInt.Function();

  Derived<long> derivedLong;
  derivedLong.Function();

  Derived<double> derivedDouble;
  derivedDouble.Function();
}

would be

overriden version 1
overriden version 2
default version

Is it possible?

like image 247
G-s Avatar asked Jun 02 '12 15:06

G-s


People also ask

How will you restrict the template for a specific datatype?

There are ways to restrict the types you can use inside a template you write by using specific typedefs inside your template. This will ensure that the compilation of the template specialisation for a type that does not include that particular typedef will fail, so you can selectively support/not support certain types.

Can we override template function in C++?

You may overload a function template either by a non-template function or by another function template. The function call f(1, 2) could match the argument types of both the template function and the non-template function.

Is function template overloading possible?

A template function can be overloaded either by a non-template function or using an ordinary function template.

Does template allow us to define generic classes and functions?

A C++ template is a powerful feature added to C++. It allows you to define the generic classes and generic functions and thus provides support for generic programming. Generic programming is a technique where generic types are used as parameters in algorithms so that they can work for a variety of data types.


3 Answers

Member functions of class templates are in fact function templates, so you can specialize them:

template <typename T> class Foo
{
    void Function();
};

template <typename T> void Foo::Function() { /* ... */ }

template <> void Foo<int>::Function() { /* ... */ }
like image 109
Kerrek SB Avatar answered Sep 18 '22 23:09

Kerrek SB


Yes, by specializing Derived.

  • write the generic version without it (it will inherit it from Base)
  • specialize Derived to override

Simple scheme, but it works.

like image 44
Matthieu M. Avatar answered Sep 19 '22 23:09

Matthieu M.


First solution (use of the typeid operator):

#include <iostream>
#include <typeinfo>

using namespace std;

class Base
{
public:
    virtual void Function();
};

void Base::Function()
{
    cout << "default version\n";
}

template<typename T>
class Derived : Base
{
public:
    virtual void Function();
};

template<typename T>
void Derived<T>::Function()
{
    if(typeid(T) == typeid(int)) // check if T is an int
    {
        cout << "overriden version 1\n";
    }
    else if(typeid(T) == typeid(long)) // check if T is a long int
    {
        cout << "overriden version 2\n";
    }
    else // if T is neither an int nor a long
    {
        Base::Function(); // call default version
    }
}

int main()
{
    Derived<int> di;
    Derived<long> dl;
    Derived<float> df;

    di.Function();
    dl.Function();
    df.Function();

    return 0;
}

I use the typeid operator to check if T is either an int or a long int, and if it is, I print "overriden version [number]". If it is not, I call Base::Function(), which will print "default version"

Note: to use the typeid operator you need to include the header file typeinfo

Second solution (using template specializations):

// class declarations as before

template<typename T>
void Derived<T>::Function()
{
    Base::Function(); // call default version
}

template<>
void Derived<int>::Function()
{
    cout << "overriden version 1\n";
}

template<>
void Derived<long>::Function()
{
    cout << "overriden version 2\n";
}

int main()
{
    Derived<int> di;
    Derived<long> dl;
    Derived<float> df;

    di.Function();
    dl.Function();
    df.Function();

    return 0;
}

Here, I solve your problem with template specializations. If T is either an int or a long int, I call the specialized versions. Else, i call the general version, which is equivalent to Base::Function().

like image 21
Rontogiannis Aristofanis Avatar answered Sep 21 '22 23:09

Rontogiannis Aristofanis