I have a functor Foo
defined as follows:
struct Foo {
template <typename _Vector>
void operator()(const Eigen::Ref<const _Vector>&, const Eigen::Ref<const _Vector>&) {
/* ... */
}
};
I'd like to call it with either Eigen vectors, blocks, or Eigen::Ref, and _Vector
can be any of Eigen vector types. This implementation doesn't work because you must call it exactly with Eigen::Ref<const _Vector>
arguments -- and not, for instance, with vectors, or segments of vectors. A workaround I found is the following:
struct Foo {
/* This works, but I'm not sure if it is the most correct solution. */
template <typename T, typename U>
void operator()(const T& x, const U& y) {
Impl<typename T::PlainObject>(x, y);
}
/* This doesn't work, but I expected this to be the most correct solution. */
// template <typename T, typename U>
// void operator()(T&& x, U&& y) {
// Impl<typename T::PlainObject>(std::forward<T>(x), std::forward<U>(y));
// }
template <typename _Vector>
void Impl(const Eigen::Ref<const _Vector>&, const Eigen::Ref<const _Vector>&) {
/* ... */
}
};
Here, I hide the implementation inside a function Impl
and catch every argument with operator()
; then, I deduce the right _Vector
type from the member type PlainObject
of the first argument (x
). However, I expect the commented code to be more "correct" since it perfectly forwards the arguments, so that they are used by Impl
being exactly as they were supposed to be. Is this assertion wrong? Unfortunately, it fails with the following error:
error: ‘Eigen::Ref<Eigen::Matrix<double, -1, 1> >&’ is not a class, struct, or union type
[build] 390 | Impl<typename T::PlainObject>(std::forward<T>(x), std::forward<U>(y));
[build] | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
It states that Eigen::Ref
is not a class, struct, or union type; but it actually is a class. How can this error be solved?
P.S.: I must confess that I'm not 100% confident I understood when T&&
and std::forward
should be used. My understanding is that they give you exactly what you pass with no extra copies or implicit conversions.
error: ‘Eigen::Ref<Eigen::Matrix<double, -1, 1> >&’ is not a class, struct, or union type ^
You need to std::remove_reference
to make the version with perfect forwarding valid:
#include <type_traits>
template <typename T, typename U>
void operator()(T&& x, U&& y) {
Impl<typename std::remove_reference_t<T>::PlainObject>(std::forward<T>(x),
std::forward<U>(y));
}