Reputation: 478
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.
Upvotes: 1
Views: 727
Reputation: 937
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.
Upvotes: 1
Reputation: 29205
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);
}
Upvotes: 3