Search code examples
c++eigen

Taking Eigen::Vector as a parameter


I am trying to write a function that takes an Eigen::Vector<T, dim> as a parameter. However, the following example fails to compile:

#include <Eigen/Core>

template<class F, typename T, int dim>
void bar(F&& func, const Eigen::Vector<T, dim>& arg1) {
}

template<typename T, int dim>
void foo(const Eigen::Vector<T, dim>& a) {
  return bar([] {}, a);
}

int main() {
  Eigen::Vector<float, 3> v1{ 1.f,2.f,3.f };
  foo(v1);
  return 0;
}

This, under Visual Studio 2019, gives me the following error:

1>main.cpp(9,10): error C2672:  'bar': no matching overloaded function found
1>main.cpp(14): message :  see reference to function template instantiation 'void foo<float,3>(const Eigen::Matrix<float,3,1,0,3,1> &)' being compiled
1>main.cpp(9,1): error C2784:  'void bar(F &&,const Eigen::Matrix<T,dim,1,|_Rows==&&?:&&_Rows!=?:,_Rows,1> &)': could not deduce template argument for 'const Eigen::Matrix<T,dim,1,|_Rows==&&?:&&_Rows!=?:,_Rows,1> &' from 'const Eigen::Matrix<float,3,1,0,3,1>'
1>main.cpp(4): message :  see declaration of 'bar'

My questions:

  • What is this weird |_Rows==&&?:&&_Rows!=?: in the error message?
  • What can I do to make the above code compile?

The bar function should have T and dim availabe. I cannot just take const AnyType& arg1, because the actual implementation of bar depends on compile-time known values T and dim.

I have seen https://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html. I think I understand what they are saying, but I am not sure if it applies here. I am taking an actual Eigen::Vector as an argument, not an expression.

If there was an expression it would be fine for me, to have it materialized.

Nevertheless, if I try to follow their instruction and just use ArrayBase<Derived>, I lose the compile-time information about T and dim.


Solution

  • This indeed looks like an MSVC issue, it compiles fine with gcc >= 4.7, and clang >= 3.5: https://godbolt.org/z/kqoHyO

    One possible workaround would be to explicitly write out what Eigen::Vector expands to:

    template<class F, typename T, int dim>
    void bar(F&& func, const Eigen::Matrix<T, dim, 1, 0, dim, 1>& arg1) {
    }
    

    https://godbolt.org/z/vlvSDP

    The weird |_Rows==&&?:&&_Rows!=?: looks like MSVC mangled the default value of the Options template parameter:

              AutoAlign |
                          ( (_Rows==1 && _Cols!=1) ? Eigen::RowMajor
                          : (_Cols==1 && _Rows!=1) ? Eigen::ColMajor
                          : EIGEN_DEFAULT_MATRIX_STORAGE_ORDER_OPTION ),
    

    If you want to get to the bottom of this, you should file a bug-report to the MSVC maintainers, maybe using a simplified example like this: https://godbolt.org/z/U_0Sh7 (probably it's possible to reduce this even more).