Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Template specialization for std::less in C++11, using a template

I have a Matrix class that derives from an Eigen template:

template<typename T,
         int _Rows = Eigen::Dynamic,
         int _Cols = Eigen::Dynamic>
class Matrix : public Eigen::Matrix<T, _Rows, _Cols>

I need to use this type as a key for an std::map container, hence I need a comparator object. I would like to specialize std::less for this purpose. A draft version that does not compile looks like this, to get you the idea:

template<typename Matrix<typename T,
                         int _Rows = Eigen::Dynamic,
                         int _Cols = Eigen::Dynamic> > >
struct less
{
    bool operator()(const Matrix<T,
                                 Rows,
                                 Cols>& lhs,
                    const Matrix<T,
                                 Rows,
                                 Cols>& rhs) const;
    {
      Matrix<T,
             Rows,
             Cols>::const_iterator lhsIt = lhs.begin();
      Matrix<T,
             Rows,
             Cols>::const_iterator rhsIt = rhs.begin();
      for (;
           lhsIt != lhs.end();
           ++lhsIt, ++rhsIt)
      {
        if (*lhsIt < *rhsIt)
        {
          return true;
        }
      }
      return false;
    }
};

The problem is that I want to specialize std::less using a template. What is a correct way to code this ? Do I have to resort to template specialization ?

I will also need to specialize std::hash in a similar way to be able to use std::map.

like image 226
vkubicki Avatar asked Aug 28 '15 07:08

vkubicki


People also ask

How do you define a template specialization in C++?

The act of creating a new definition of a function, class, or member of a class from a template declaration and one or more template arguments is called template instantiation. The definition created from a template instantiation is called a specialization.

What is the specialty of a template function give example?

Template in C++is a feature. We write code once and use it for any data type including user defined data types. For example, sort() can be written and used to sort any data type items. A class stack can be created that can be used as a stack of any data type.

How do you use template arguments in C++?

A template argument for a template template parameter is the name of a class template. When the compiler tries to find a template to match the template template argument, it only considers primary class templates. (A primary template is the template that is being specialized.)

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.


2 Answers

The problem is that I want to specialize std::less using a template.

Don't. std::less means "call the < operator" for this class"; specializing it for a class with no < operator is needlessly confusing to others reading your code, and specializing it for a class with a < operator is pointless.

Just implement a correct operator< overload, and you can use it in std::map.

I will also need to specialize std::hash in a similar way to be able to use std::map.

No, you don't. That's only needed for unordered_map.

By the way, your comparison algorithm is wrong. It reports [2, 1] < [1, 2] and [1, 2] < [2, 1]. Not to mention that it doesn't handle the case when the two matrices have different numbers of elements.

like image 85
T.C. Avatar answered Oct 20 '22 01:10

T.C.


The correct syntax is

template <typename T, int Row, int Col>
struct less<Matrix<T, Row, Col>>
{
    bool operator()(const Matrix<T, Row, Col>& lhs,
                    const Matrix<T, Row, Col>& rhs) const
    {
        // implementation:
        return lexicographical_compare(lhs.begin(), lhs.end(), rhs.begin(), rhs.end());
    }
};

which is a specialization.

BTW, your implementation doesn't respect less requirement: (it is not symmetric).

like image 27
Jarod42 Avatar answered Oct 20 '22 03:10

Jarod42