Search code examples
c++c++14sfinaetype-traitstemplate-argument-deduction

constexpr check of a type


I'm trying to overload some function based on whether or not I'm passing an Eigen matrix to them, and I wanted to make myself some nice constexpr function to improve readability.

For that I decided to emulate the implementation of std::is_same given on https://en.cppreference.com/w/cpp/types/is_same

template<class T, class U>
struct is_same : std::false_type {};

template<class T>
struct is_same<T, T> : std::true_type {};

And I told myself sure, easy enough:

template <typename T>
bool constexpr is_eigen() { return false; }

template <typename T, typename Eigen::Matrix<typename T::Scalar,
                                             T::RowsAtCompileTime,
                                             T::ColsAtCompileTime,
                                             T::Options,
                                             T::MaxRowsAtCompileTime,
                                             T::MaxColsAtCompileTime>>
bool constexpr is_eigen() { return true; }

However my Eigen types resolve to the first template specialization, not the first (putting a dummy typename U doesn't help).

I also tried something like:

template <typename T, bool is_it = std::is_same<T,
                                                Eigen::Matrix<typename T::Scalar,
                                                              T::RowsAtCompileTime,
                                                              T::ColsAtCompileTime,
                                                              T::Options,
                                                              T::MaxRowsAtCompileTime,
                                                              T::MaxColsAtCompileTime>>::value>
bool constexpr is_eigen() { return is_it; }

template <typename T, typename = std::enable_if_t<!std::is_class<T>::value>>
bool constexpr is_eigen() { return false; }

But for non-Eigen classes the first overload doesn't resolve, and trying anything to change that means Eigen will still hit the false branch

Basically, any default branch I come up with gets taken even for Eigen-types. I hate SFINAE :(


Solution

  • You can use partial specialization to match a Eigen::Matrix<...> like so

    template <typename T>
    struct is_eigen_impl : std::false_type {};
    
    template <typename T, int... Is>
    struct is_eigen_impl<Eigen::Matrix<T, Is...>> : std::true_type {};
    
    template <typename T>
    constexpr bool is_eigen = is_eigen_impl<T>::value;