Search code examples
c++eigen

Specialize a function for Eigen types


I'm writing a templated sparse container class and would like to check if incoming data equals zero. The data type will either be an integer or a fixed size Eigen type.

#include <Eigen/Core>

template<typename T>
struct SparseContainer
{
    void insert(const T& value)
    {
        if(isZero(value))
            return;
        // ...
    }
};

int main(int argc, char* argv[])
{
    SparseContainer<int> a;
    a.insert(1);

    SparseContainer<Eigen::Vector2i> b;
    b.insert(Eigen::Vector2i(1, 0));
}

How do I provide the isZero() function so that it works with integers and Eigen types by default, and can be extended by users of the class for their own types. I don't use boost, but C++11(i.e. std::enable_if) is ok.


Solution

  • Based on https://stackoverflow.com/a/22726414/6870253:

    #include <Eigen/Core>
    #include <iostream>
    #include <type_traits>
    
    namespace is_eigen_detail {
        // These functions are never defined.
        template <typename T>
        std::true_type test(const Eigen::EigenBase<T>*);
        std::false_type test(...);
    }
    
    template <typename T>
    struct is_eigen_type : public decltype(is_eigen_detail::test(std::declval<T*>()))
    {};
    
    template<class T>
    typename std::enable_if<is_eigen_type<T>::value, bool>::type isZero(const T& x) { return x.isZero(); }
    
    template<class T>
    typename std::enable_if<!is_eigen_type<T>::value, bool>::type isZero(const T& x) { return x == 0; }
    
    int main()
    {
        Eigen::Vector3d a;
        Eigen::Array3d b;
    
        a.setZero();
        b.setRandom();
    
        std::cout << "a: " << isZero(a) << "\nb: " << isZero(b) << "\n0.0: " << isZero(0.0) << std::endl;
    }
    

    N.B.: Of course you can use Eigen::MatrixBase or Eigen::DenseBase instead of Eigen::EigenBase, if you only want to specialize for matrices or matrices and arrays.