Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Restrict Template Function

Tags:

c++

templates

I wrote a sample program at http://codepad.org/ko8vVCDF that uses a template function.

How do I retrict the template function to only use numbers? (int, double etc.)

#include <vector>
#include <iostream>

using namespace std;

    template <typename T>
T sum(vector<T>& a)
{
    T result = 0;
    int size = a.size();
    for(int i = 0; i < size; i++)
    {
        result += a[i];
    }

    return result;
}

int main()
{
    vector<int> int_values;
    int_values.push_back(2);
    int_values.push_back(3);
    cout << "Integer: " << sum(int_values) << endl;

    vector<double> double_values;
    double_values.push_back(1.5);
    double_values.push_back(2.1);
    cout << "Double: " << sum(double_values);

    return 0;
}
like image 880
Lennie De Villiers Avatar asked Sep 29 '08 11:09

Lennie De Villiers


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 cannot define a virtual template method. override only works for virtual methods, and you can only override methods with the same signature. method<bool>() is not the same as method<int>() .

Can template function be overloaded?

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.

What does template <> mean in C++?

It's a specialization. template<> means that the specialization itself is not templated- i.e., it is an explicit specialization, not a partial specialization.


2 Answers

This is possible by using SFINAE, and made easier by using helpers from either Boost or C++11

Boost:

#include <vector>
#include <boost/utility/enable_if.hpp>
#include <boost/type_traits/is_arithmetic.hpp>

template<typename T> 
    typename boost::enable_if<typename boost::is_arithmetic<T>::type, T>::type 
        sum(const std::vector<T>& vec)
{
  typedef typename std::vector<T>::size_type size_type;
  T result;
  size_type size = vec.size();
  for(size_type i = 0; i < size; i++)
  {
    result += vec[i];
  }

  return result;
}

C++11:

#include <vector>
#include <type_traits>

template<typename T> 
    typename std::enable_if<std::is_arithmetic<T>::value, T>::type 
        sum(const std::vector<T>& vec)
{
  T result;
  for (auto item : vec)
    result += item;
  return result;
}
like image 76
Leon Timmermans Avatar answered Oct 22 '22 07:10

Leon Timmermans


The only way to restrict a template is to make it so that it uses something from the types that you want, that other types don't have.

So, you construct with an int, use + and +=, call a copy constructor, etc.

Any type that has all of these will work with your function -- so, if I create a new type that has these features, your function will work on it -- which is great, isn't it?

If you want to restrict it more, use more functions that only are defined for the type you want.

Another way to implement this is by creating a traits template -- something like this

template<class T>
SumTraits
{
public:
  const static bool canUseSum = false;
}

And then specialize it for the classes you want to be ok:

template<>
class SumTraits<int>
{
  public:
    const static bool canUseSum = true;
};

Then in your code, you can write

if (!SumTraits<T>::canUseSum) {
   // throw something here
}

edit: as mentioned in the comments, you can use BOOST_STATIC_ASSERT to make it a compile-time check instead of a run-time one

like image 31
Lou Franco Avatar answered Oct 22 '22 06:10

Lou Franco