1
votes

How can I write a function that takes both fundamental data types (int, float, double, …) and Eigen library types (Vector2f, Vector4d, Matrix4f, …)? Specifically, I want a cast function that casts the provided parameter to type N.

For example:

float x1 = cast<float>(1);
double x2 = cast<double>(2.0);
Vector2d x3 = cast<double>(Vector2f(3.0f, 3.0f));
Vector2f x4 = cast<float>(Vector2i(4, 4));

The easy part:

template<typename T, typename N>
N cast(const T& source) const
{
    return static_cast<N>(source);
}

Casting an Eigen type:

template<typename T, typename N>
Eigen::CwiseUnaryOp<Eigen::internal::scalar_cast_op<typename Eigen::internal::traits<T>::Scalar, N>, const T> cast(const Eigen::MatrixBase<T>& source) const
{
    return source.cast<N>();
}

In Eigen, a cast from Vector2f v to Vector2d is done with v.cast<double>(), so the template parameter is the data type of the scalar, not the new type itself.

The trouble that I have (at least I think that's the main issue) is that I don't know how I can put these two templates together. The Eigen one should probably be a specialization of the first one, but is this even possible? The templates themselves compile, but e.g. cast<Vector2f, double>(Vector2f::Zero()) will not, because 'static_cast' : cannot convert from 'const Eigen::Vector2f' to 'double'.

What to do? C++11 solutions are very welcome, but please type slowly, as I am no template wizard.

Update: The reason I need this is that I want to be able to conveniently cast the contents of containers, std::vector<T> to std::vector<N>, for example std::vector<Vector2f> to std::vector<Vector2d>, but also from std::vector<float> to std::vector<double>. For this, I loop over all elements and cast each one with the required function. So if there's a better way to cast a std::vector of Eigen types, this would be what I need.

2

2 Answers

3
votes

You can use std::enable_if to limit the general version to arithmetic types only:

template<typename T, typename N>
typename std::enable_if<std::is_arithmetic<T>::value,N>::type
cast(const T& source) const {
  return static_cast<N>(source);
}
1
votes

With C++17, there is another solution, which I personally find more elegant, using if constexpr:

template<typename T, typename N>
std::conditional<std::is_arithmetic<T>::value, N, /* your Eigen return type here */>::type
cast( const T& source ) {
    if constexpr( std::is_arithmetic<T>::value )
        return static_cast<N>(source);
    else
        /* Eigen cast */
}

That way, it's all in one function, and I find the syntax a bit clearer.