Related
I'm looking to make a loss function that can take 2 tensors of any dimensions as parameters, but the dimensions of tensor 1 (t1) and tensor (t2) must match. Below are the templates that I tried to use to can pass the tensors into the function. I was thinking that T would be a type and N would model the number of indexes possible without explicitly writing a type for infinitely possible tensor dimensions.
loss.h
#include <iostream>
namespace Loss {
template<class T, std::size_t N>
void loss(Eigen::Tensor<T, N, 0>& predicted, Eigen::Tensor<T, N, 0>& actual) {
std::cout << "Loss::loss() not implemented" << std::endl;
};
};
main.cpp
#include "loss.h"
int main() {
Eigen::Tensor<double, 3> t1(2, 3, 4);
Eigen::Tensor<double, 3> t2(2, 3, 4);
t1.setZero();
t2.setZero();
Loss::loss(t1, t2);
return 0;
}
The type error that I get before compiling from my editor:
no instance of function template "Loss::loss" matches the argument list -- argument types are: (Eigen::Tensor<double, 3, 0, Eigen::DenseIndex>, Eigen::Tensor<double, 3, 0, Eigen::DenseIndex>
And this is the message I get once I compile (unsuccessfully):
note: candidate template ignored: substitution failure [with T = double]: deduced non-type template argument does not have the same type as the corresponding template parameter ('int' vs 'std::size_t' (aka 'unsigned long'))
void loss(Eigen::Tensor<T, N, 0>& predicted, Eigen::Tensor<T, N, 0>& actual) {
^
1 error generated.
The error message is pointing out the type of the non-type template parameter is size_t, but in the declaration of t1 and t2 the value of that parameter is 3, which has type int. This mismatch makes the template argument deduction fail.
You can fix this by changing the type of the non-type template parameter to int
template<class T, int N>
void loss( // ...
or just let it be deduced
template<class T, auto N>
void loss( // ...
number literals are signed integers, and you’ve specified the number type of your template as size_t Which is unsigned. So the types don’t match. Try Eigen::Tensor<double, 3u> … in your main program to use unsigned literals.
The following program does not compile:
template <unsigned int dim, unsigned int N, bool P, bool C, class... ParametersType>
void test(ParametersType&&... par)
{
}
int main()
{
test<2, 3, true, false>(2, 1, {8, 8});
}
See it live on Coliru.
The error message
g++ -std=c++17 -O1 -Wall -pedantic -pthread main.cpp && ./a.out
main.cpp: In function 'int main()':
main.cpp:8:41: error: too many arguments to function 'void test(ParametersType&& ...)
[with unsigned int dim = 2; unsigned int N = 3; bool P = true; bool C = false; ParametersType = {}]'
8 | test<2, 3, true, false>(2, 1, {8, 8});
| ^
main.cpp:2:6: note: declared here
2 | void test(ParametersType&&... par)
| ^~~~
indicates that the parameter pack ParametersType... is deduced to an empty one, while I would expect it to be deduced according to the types of the arguments passed to test.
The problem is in the {8, 8} parameter passed to test.
Explicitly passing a std::array to the function solves the problem:
#include <array>
template <unsigned int dim, unsigned int N, bool P, bool C, class... ParametersType>
void test(ParametersType&&... par)
{
}
int main()
{
test<2, 3, true, false>(2, 1, std::array<int, 2>{8, 8});
}
See it live on Coliru.
Why does the compiler apparently incorrectly deduces the pack in the first example?
If the compiler is not able to deduce {8, 8} to an std::array, I would expect an "impossible to deduce" error. Why instead does the compiler deduce the pack to an empty one?
Template errors are hard to get right. It's just a quality of implementation. Clang for instances gives
main.cpp:2:6: note: candidate template ignored: substitution failure
[with dim = 2, N = 3, P = true, C = false]: deduced incomplete pack <int, int, (no value)>
for template parameter 'ParametersType'
which is easier to understand. And yes, unless using auto, {stuff} has no type.
From cppreference:
A braced-init-list is not an expression and therefore has no type,
e.g. decltype({1,2}) is ill-formed. Having no type implies that
template type deduction cannot deduce a type that matches a
braced-init-list, so given the declaration template void
f(T); the expression f({1,2,3}) is ill-formed.
You can also use auto in this context to fix your issue:
template <unsigned int dim, unsigned int N, bool P, bool C, class... ParametersType>
void test(ParametersType&&... par)
{
}
int main()
{
auto x = { 8, 8 };
test<2, 3, true, false>(2, 1, x);
}
I'm working on adding Sparse matrix support to an open source math library and would like to not have duplicated functions for both Dense and Sparse matrix types.
The below example shows an add function. A working example with two functions, then two attempts that failed. A godbolt link to the code examples are available below.
I've looked over the Eigen docs on writing functions that take Eigen types but their answers of using Eigen::EigenBase does not work because both MatrixBase and SparseMatrixBase have particular methods available that do not exist in EigenBase
https://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html
We use C++14, any help and your time is very appreciated!!
#include <Eigen/Core>
#include <Eigen/Sparse>
#include <iostream>
// Sparse matrix helper
using triplet_d = Eigen::Triplet<double>;
using sparse_mat_d = Eigen::SparseMatrix<double>;
std::vector<triplet_d> tripletList;
// Returns plain object
template <typename Derived>
using eigen_return_t = typename Derived::PlainObject;
// Below two are the generics that work
template <class Derived>
eigen_return_t<Derived> add(const Eigen::MatrixBase<Derived>& A) {
return A + A;
}
template <class Derived>
eigen_return_t<Derived> add(const Eigen::SparseMatrixBase<Derived>& A) {
return A + A;
}
int main()
{
// Fill up the sparse and dense matrices
tripletList.reserve(4);
tripletList.push_back(triplet_d(0, 0, 1));
tripletList.push_back(triplet_d(0, 1, 2));
tripletList.push_back(triplet_d(1, 0, 3));
tripletList.push_back(triplet_d(1, 1, 4));
sparse_mat_d mat(2, 2);
mat.setFromTriplets(tripletList.begin(), tripletList.end());
Eigen::Matrix<double, -1, -1> v(2, 2);
v << 1, 2, 3, 4;
// Works fine
sparse_mat_d output = add(mat * mat);
std::cout << output;
// Works fine
Eigen::Matrix<double, -1, -1> output2 = add(v * v);
std::cout << output2;
}
Instead of the two add functions I would just like to have one that takes in both sparse and dense matrices, but the attempts below have not worked out.
Template Template type
An obviously poor attempt on my part, but replacing the two add functions above with a template template type causes an ambiguous base class error.
template <template <class> class Container, class Derived>
Container<Derived> add(const Container<Derived>& A) {
return A + A;
}
Error:
<source>: In function 'int main()':
<source>:35:38: error: no matching function for call to 'add(const Eigen::Product<Eigen::SparseMatrix<double, 0, int>, Eigen::SparseMatrix<double, 0, int>, 2>)'
35 | sparse_mat_d output = add(mat * mat);
| ^
<source>:20:20: note: candidate: 'template<template<class> class Container, class Derived> Container<Derived> add(const Container<Derived>&)'
20 | Container<Derived> add(const Container<Derived>& A) {
| ^~~
<source>:20:20: note: template argument deduction/substitution failed:
<source>:35:38: note: 'const Container<Derived>' is an ambiguous base class of 'const Eigen::Product<Eigen::SparseMatrix<double, 0, int>, Eigen::SparseMatrix<double, 0, int>, 2>'
35 | sparse_mat_d output = add(mat * mat);
| ^
<source>:40:52: error: no matching function for call to 'add(const Eigen::Product<Eigen::Matrix<double, -1, -1>, Eigen::Matrix<double, -1, -1>, 0>)'
40 | Eigen::Matrix<double, -1, -1> output2 = add(v * v);
| ^
<source>:20:20: note: candidate: 'template<template<class> class Container, class Derived> Container<Derived> add(const Container<Derived>&)'
20 | Container<Derived> add(const Container<Derived>& A) {
| ^~~
<source>:20:20: note: template argument deduction/substitution failed:
<source>:40:52: note: 'const Container<Derived>' is an ambiguous base class of 'const Eigen::Product<Eigen::Matrix<double, -1, -1>, Eigen::Matrix<double, -1, -1>, 0>'
40 | Eigen::Matrix<double, -1, -1> output2 = add(v * v);
| ^
I believe It's the same diamond inheritance problem from here:
https://www.fluentcpp.com/2017/05/19/crtp-helper/
Using std::conditional_t
The below attempts to use conditional_t to deduce the correct input type
#include <Eigen/Core>
#include <Eigen/Sparse>
#include <iostream>
// Sparse matrix helper
using triplet_d = Eigen::Triplet<double>;
using sparse_mat_d = Eigen::SparseMatrix<double>;
std::vector<triplet_d> tripletList;
// Returns plain object
template <typename Derived>
using eigen_return_t = typename Derived::PlainObject;
// Check it Object inherits from DenseBase
template<typename Derived>
using is_dense_matrix_expression = std::is_base_of<Eigen::DenseBase<std::decay_t<Derived>>, std::decay_t<Derived>>;
// Check it Object inherits from EigenBase
template<typename Derived>
using is_eigen_expression = std::is_base_of<Eigen::EigenBase<std::decay_t<Derived>>, std::decay_t<Derived>>;
// Alias to deduce if input should be Dense or Sparse matrix
template <typename Derived>
using eigen_matrix = typename std::conditional_t<is_dense_matrix_expression<Derived>::value,
typename Eigen::MatrixBase<Derived>, typename Eigen::SparseMatrixBase<Derived>>;
template <typename Derived>
eigen_return_t<Derived> add(const eigen_matrix<Derived>& A) {
return A + A;
}
int main()
{
tripletList.reserve(4);
tripletList.push_back(triplet_d(0, 0, 1));
tripletList.push_back(triplet_d(0, 1, 2));
tripletList.push_back(triplet_d(1, 0, 3));
tripletList.push_back(triplet_d(1, 1, 4));
sparse_mat_d mat(2, 2);
mat.setFromTriplets(tripletList.begin(), tripletList.end());
sparse_mat_d output = add(mat * mat);
std::cout << output;
Eigen::Matrix<double, -1, -1> v(2, 2);
v << 1, 2, 3, 4;
Eigen::Matrix<double, -1, -1> output2 = add(v * v);
std::cout << output2;
}
This throws the error
<source>: In function 'int main()':
<source>:94:38: error: no matching function for call to 'add(const Eigen::Product<Eigen::SparseMatrix<double, 0, int>, Eigen::SparseMatrix<double, 0, int>, 2>)'
94 | sparse_mat_d output = add(mat * mat);
| ^
<source>:79:25: note: candidate: 'template<class Derived> eigen_return_t<Derived> add(eigen_matrix<Derived>&)'
79 | eigen_return_t<Derived> add(const eigen_matrix<Derived>& A) {
| ^~~
<source>:79:25: note: template argument deduction/substitution failed:
<source>:94:38: note: couldn't deduce template parameter 'Derived'
94 | sparse_mat_d output = add(mat * mat);
| ^
<source>:99:52: error: no matching function for call to 'add(const Eigen::Product<Eigen::Matrix<double, -1, -1>, Eigen::Matrix<double, -1, -1>, 0>)'
99 | Eigen::Matrix<double, -1, -1> output2 = add(v * v);
| ^
<source>:79:25: note: candidate: 'template<class Derived> eigen_return_t<Derived> add(eigen_matrix<Derived>&)'
79 | eigen_return_t<Derived> add(const eigen_matrix<Derived>& A) {
| ^~~
<source>:79:25: note: template argument deduction/substitution failed:
<source>:99:52: note: couldn't deduce template parameter 'Derived'
99 | Eigen::Matrix<double, -1, -1> output2 = add(v * v);
This seems to be because dependent parameters of dependent types can't be deduced like this link goes over.
https://deque.blog/2017/10/12/why-template-parameters-of-dependent-type-names-cannot-be-deduced-and-what-to-do-about-it/
Godbolt Example
The godbolt below has all of the instances above to play with
https://godbolt.org/z/yKEAsn
Is there some way to only have one function instead of two? We have a lot of functions that can support both sparse and dense matrices so it would be nice to avoid the code duplication.
Edit: Possible Answer
#Max Langhof suggested using
template <class Mat>
auto add(const Mat& A) {
return A + A;
}
The auto keyword is a bit dangerous with Eigen
https://eigen.tuxfamily.org/dox/TopicPitfalls.html
But
template <class Mat>
typename Mat::PlainObject add(const Mat& A) {
return A + A;
}
works, though tbh I'm not entirely sure why returning a plain object works in this scenario
Edit Edit
Several people have mentioned the use of the auto keyword. Sadly Eigen does not play well with auto as referenced in the second on C++11 and auto in the link below
https://eigen.tuxfamily.org/dox/TopicPitfalls.html
It's possible to use auto for some cases, though I'd like to see if there is a generic auto'ish way that is complaint for Eigen's template return types
For an example of a segfault with auto you can try replace add with
template <typename T1>
auto add(const T1& A)
{
return ((A+A).eval()).transpose();
}
If you want to pass EigenBase<Derived>, you can extract the underlying type using .derived() (essentially, this just casts to Derived const&):
template <class Derived>
eigen_return_t<Derived> add(const Eigen::EigenBase<Derived>& A_) {
Derived const& A = A_.derived();
return A + A;
}
More advanced, for this particular example, since you are using A twice, you can express that using the internal evaluator structure:
template <class Derived>
eigen_return_t<Derived> add2(const Eigen::EigenBase<Derived>& A_) {
// A is used twice:
typedef typename Eigen::internal::nested_eval<Derived,2>::type NestedA;
NestedA A (A_.derived());
return A + A;
}
This has the advantage that when passing a product as A_ it won't get evaluated twice when evaluating A+A, but if A_ is something like a Block<...> it will not get copied unnecessarily. However, using internal functionality is not really recommended (the API of that could change at any time).
The problem of your compiler is the following:
couldn't deduce template parameter 'Derived'
Passing the required type for Derived should probably work, like follows:
add<double>(v * v)
However I'm not sure because Eigen::Matrix is not the same type as Eigen::MatrixBase as it appears to me.
However, if you restrict the compiler less on the type, it will be able to figure out the type:
template <typename T>
auto add(const T& A) {
return A + A;
}
Edit:
Just saw in the comments that this solution has already been posted and that the Eigen documentation recommends to not use auto. I am not familiar with Eigen, but as it appears to me from skimming over the documentation, it could be that Eigen produces results which represent expressions - e.g. an object representing the matrix addition as an algorithm; not the matrix addition result itself. In this case, if you know that A + A results in type T (which it actually should for operator+ in my opinion) you could write it like follows:
template <typename T>
T add(const T& A) {
return A + A;
}
In the matrix example, this should force a matrix result to be returned; not the object representing the expression. However, since you have been originally using eigen_result_t, I'm not 100% sure.
I haven't understood all of your code and comments. Anyways, it seems that your problem reduces to finding a way to write a function which can accept serveral matrix types.
template <typename T>
auto add(const T& A)
{
return 2*A;
}
You can also add 2 matrices of different types:
template <typename T1, typename T2>
auto add(const T1& A, const T2& B) -> decltype(A+B) // decltype can be omitted since c++14
{
return A + B;
}
Then, add(A,A) gives the same result as add(A). But the add function with 2 arguments makes more sense I think. And it's more versatile as you can sum a sparse matrix with a dense matrix.
int main()
{
constexpr size_t size = 10;
Eigen::SparseMatrix<double> spm_heap(size,size);
Eigen::MatrixXd m_heap(size,size);
Eigen::Matrix<double,size,size> m_stack;
// fill the matrices
std::cout << add(spm_heap,m_heap);
std::cout << add(spm_heap,m_stack);
return 0;
}
EDIT
About the edit where you state that auto should not be used with Eigen. This is quite interesting!
template <typename T>
auto add(const T& A)
{
return ((A+A).eval()).transpose();
}
This produces a segfault. Why? auto does deduce the type well, but the deduced type is not decltype(A), but a reference of that type. Why? I first thought it was because of the parentheses around the return value (read here if interested), but it seems to be due to the return type of the transpose function.
Anyways, it is easy to overcome that problem. As you suggested, you could remove auto:
template <typename T>
T add(const T& A)
{
return ((A+A).eval()).transpose();
}
Or, you could use auto but specifying the desired return type:
template <typename T>
auto add(const T& A) -> typename std::remove_reference<decltype(A)>::type // or simply decltype(A.eval())
{
return ((A+A).eval()).transpose();
}
Now, for this particular add function, the first option (omitting auto) is the best solution. However, for the other add function which takes 2 arguments of different types, this is quite a good solution:
template <typename T1, typename T2>
auto add(const T1& A, const T2& B) -> decltype((A+B).eval())
{
return ((A+B).eval()).transpose();
}
I am interested in printing out a variadic number of templated arguments.
So far I have implemented the code below but run into the following compile-time errors
./include/AView.hpp:46:5: error: call to member function 'indexcalc2' is ambiguous
indexcalc2<Strs...>();
^~~~~~~~~~~~~~~~~~~
./include/AView.hpp:46:5: note: in instantiation of function template specialization 'myView<double, 2, 1, 2, 3, 4,
5>::indexcalc2<4, 5>' requested here
./include/AView.hpp:46:5: note: in instantiation of function template specialization 'myView<double, 2, 1, 2, 3, 4,
5>::indexcalc2<3, 4, 5>' requested here
./include/AView.hpp:52:5: note: in instantiation of function template specialization 'myView<double, 2, 1, 2, 3, 4,
5>::indexcalc2<2, 3, 4, 5>' requested here
indexcalc2<Strides...>();
^
main.cpp:23:9: note: in instantiation of member function 'myView<double, 2, 1, 2, 3, 4, 5>::indexcalc' requested here
A.indexcalc();
^
./include/AView.hpp:36:8: note: candidate function [with Str0 = 5]
void indexcalc2() const
^
./include/AView.hpp:43:8: note: candidate function [with Str0 = 5, Strs = <>]
void indexcalc2() const
The idea here is to create a layout struct with a get method that will output the first template argument stride. I then created a second struct called view with an indexcalc method which would generate a layout, print the stride, and recursively peal template arguments by calling indexcalc2.
Unfortunately, I don't quite have the correct implementation and wondering if there might be suggestions.
template<size_t... Strides>
struct layout
{
static size_t get(size_t idx0) {return idx0;};
};
template<size_t stride0, size_t... Strides>
struct layout<stride0, Strides...> : layout<Strides...>
{
static size_t get()
{
std::cout<<"Stride is : "<<stride0<<std::endl;
return stride0;
}
};
template<typename T, size_t DIM,size_t Stride0, size_t... Strides>
struct myView
{
myView() {};
template<size_t Str0>
void indexcalc2() const
{
std::cout<<layout<Str0>::get()<<std::endl;
std::cout<<"End"<<std::endl;
}
template<size_t Str0, size_t... Strs>
void indexcalc2() const
{
std::cout<<layout<Str0,Strs...>::get()<<std::endl;
indexcalc2<Strs...>();
}
void indexcalc() const
{
std::cout<<layout<Stride0, Strides...>::get()<<std::endl;
indexcalc2<Strides...>();
}
};
int main()
{
struct myView<double,2,1,2,3,4,5> A;
A.indexcalc();
return 0;
}
You have multiple problems here:
template<size_t Str0> void indexcalc2() const;
template<size_t Str0, size_t... Strs> void indexcalc2() const;
will result in the same instance if Strs contains no elements. So you have an ambiguous instance here which is already complained by the compiler:
./include/AView.hpp:46:5: error: call to member function 'indexcalc2' is ambiguous
indexcalc2<Strs...>();
So the idea by unwinding a parameter set is always to have an empty specialization like:
template<> void indexcalc2() const;
so that a call from
indexcalc2<Strs...>();
goes to that specialization if Strs is empty.
But after this you will run into the next trouble:
Specialization of templates can not be done in the class scope. So you must specialize outside like:
template<> void myView::indexcalc2<>() const;
But your myView is also a template and it is not allowed to specialize your method without fully specialize the class parameters!
If you go with c++17 you simply can use constexpr ifto get rid of all that problems, but in c++11 you have to go over specializing with an encapsulating class.
Your templated class with templated methods is to complex to simply write down a complete solution here for you.
I am using Eigen, and am currently trying to write a function to operate on rows of a matrix. I've followed the guidelines in the docs but nothing I try compiles (with either clang or g++); I'm at my wits end. How should one actually write functions which will take a RowXpr?
For reference, here is what I have tried so far:
#include <iostream>
#include <Eigen/Core>
using namespace std;
using namespace Eigen;
constexpr Eigen::StorageOptions Order = ColMajor;
using vect_t = Matrix<double, 1, 3, Order>;
using matr_t = Matrix<double, Dynamic, 3, Order>;
#define FUNC 3
#if FUNC == 1
vect_t func(const vect_t& f)
{
return f;
}
#elif FUNC == 2
vect_t func(const Ref<vect_t>& f)
{
return f;
}
#elif FUNC == 3
template<class D> vect_t func(const MatrixBase<D>& f)
{
return f;
}
#endif
int main()
{
matr_t M = matr_t::Random(5,3);
cout << M << endl;
cout << func( M.row(2) ) << endl;
return 0;
}
Thanks!
Edit:
With clang (version 3.8.0-2ubuntu4) the error I get is as below. The error is comparable with g++.
dan#dan-laptop:~/workspace/scratch$ clang++ eigen_func_test.cpp -I /home/dan/Downloads/eigen_3.3.3/ --std=c++11 && ./a.out
In file included from eigen_func_test.cpp:2:
In file included from /home/dan/Downloads/eigen_3.3.3/Eigen/Core:436:
/home/dan/Downloads/eigen_3.3.3/Eigen/src/Core/PlainObjectBase.h:899:7: error: static_assert failed
"INVALID_MATRIX_TEMPLATE_PARAMETERS"
...EIGEN_STATIC_ASSERT((EIGEN_IMPLIES(MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1, (Options&RowMajor)==RowMajor)
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/home/dan/Downloads/eigen_3.3.3/Eigen/src/Core/util/StaticAssert.h:32:40: note: expanded from macro
'EIGEN_STATIC_ASSERT'
#define EIGEN_STATIC_ASSERT(X,MSG) static_assert(X,#MSG);
^ ~
/home/dan/Downloads/eigen_3.3.3/Eigen/src/Core/PlainObjectBase.h:535:7: note: in instantiation of member function
'Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 0, 1, 3> >::_check_template_params' requested here
_check_template_params();
^
/home/dan/Downloads/eigen_3.3.3/Eigen/src/Core/Matrix.h:379:9: note: in instantiation of function template
specialization 'Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 0, 1, 3>
>::PlainObjectBase<Eigen::Block<Eigen::Matrix<double, -1, 3, 0, -1, 3>, 1, 3, false> >' requested here
: Base(other.derived())
^
eigen_func_test.cpp:32:9: note: in instantiation of function template specialization 'Eigen::Matrix<double, 1, 3, 0,
1, 3>::Matrix<Eigen::Block<Eigen::Matrix<double, -1, 3, 0, -1, 3>, 1, 3, false> >' requested here
return f;
^
eigen_func_test.cpp:41:10: note: in instantiation of function template specialization
'func<Eigen::Block<Eigen::Matrix<double, -1, 3, 0, -1, 3>, 1, 3, false> >' requested here
cout << func( M.row(2) ) << endl;
^
1 error generated.
If you read the part highlighted by clang
EIGEN_STATIC_ASSERT((EIGEN_IMPLIES(MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1, (Options&RowMajor)==RowMajor)
you see that, if a matrix has one row at compile time and more than one column, it must be RowMajor. That means, if you set Order = RowMajor or just leave out the , Order in
using vect_t = Matrix<double, 1, 3, Order>;
your code should compile fine (it looks like everything else are just follow-up errors).
Not exactly sure what is causing your compiler error directly but from what you have shown in your source code as well as your compiler errors. This is the part of the compiler error message that I'm basing this off of.
/home/dan/Downloads/eigen_3.3.3/Eigen/src/Core/PlainObjectBase.h:899:7: error: static_assert failed
"INVALID_MATRIX_TEMPLATE_PARAMETERS"
So when looking at the source code you are trying to use the #define func3
that you have declared as such:
template<class D> vect_t func(const MatrixBase<D>& f) {
return f;
}
with the using directives that you have declared as:
constexpr Eigen::StorageOptions Order = ColMajor;
using vect_t = Matrix<double, 1, 3, Order>;
using matr_t = Matrix<double, Dynamic, 3, Order>;
So let's expand this to the full form to see what the compiler is trying to parse or deduce as your parameters and return type.
template<class D>
Matrix<double, 1, 3, constexpr Eigen::StorageOptions Order = ColMajor>
func( const MatrixBase<D>& f ) {
return f;
}
Then in your main you use this with:
int main() {
// matr_t M = matr_t::Random(5,3);
Matrix<double, Dynamic, 3, constexpr Eigen::StorageOptions Order = ColMajor> M
= Matrix<double, Dynamic, 3, constexpr Eigen::StorageOptions Order = ColMajor>::Random(5, 3);
// Then you call your function passing it this:
std::cout << func( M.row(2) ) << std::endl;
return 0;
}
func() is returning Matrix<double, 1, 3, Order>;
and it takes const MatrixBase<D>&
however it appears you are passing it: M.row(2)
that is constructed from: Matrix<double, Dynamic, 3, constexpr Eigen::StorageOptions Order = ColMajor>::Random(5, 3)
In the function itself you are returning f which happens to be
the function's const ref of MatrixBase<D> parameter yet the declaration is expecting to return a Matrix<double, 1, 3, Order>
So I think the compiler is having a hard time trying to convert a
Matrix<double, Dynamic, 3, Order> to a Matrix<double, 1, 3, Order>
Maybe this will help you to understand the compiler error a little better; as you can see when you look at the rest of the compilation error message you can tell that this is evident when it is trying to do the specializations of this template.