Понимание статического утверждения
К сожалению, утверждение на самом деле не говорит само за себя, и единственное, что вы можете из него получить, это намек, что что-то не так с параметрами вашего шаблона.Если мы посмотрим на исходный код Эйгена Исходный код Эйгена , мы найдем следующее начало в строке 903:
EIGEN_STATIC_ASSERT((EIGEN_IMPLIES(MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1, (Options&RowMajor)==RowMajor)
&& EIGEN_IMPLIES(MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1, (Options&RowMajor)==0)
&& ((RowsAtCompileTime == Dynamic) || (RowsAtCompileTime >= 0))
&& ((ColsAtCompileTime == Dynamic) || (ColsAtCompileTime >= 0))
&& ((MaxRowsAtCompileTime == Dynamic) || (MaxRowsAtCompileTime >= 0))
&& ((MaxColsAtCompileTime == Dynamic) || (MaxColsAtCompileTime >= 0))
&& (MaxRowsAtCompileTime == RowsAtCompileTime || RowsAtCompileTime==Dynamic)
&& (MaxColsAtCompileTime == ColsAtCompileTime || ColsAtCompileTime==Dynamic)
&& (Options & (DontAlign|RowMajor)) == Options),
INVALID_MATRIX_TEMPLATE_PARAMETERS)
Даже если компилятор указывает, что
EIGEN_IMPLIES(MaxRowsAtCompileTime==1 && MaxColsAtCompileTime!=1, (Options&RowMajor)==RowMajor)
вызываетошибка, действительно следующая строка:
EIGEN_IMPLIES(MaxColsAtCompileTime==1 && MaxRowsAtCompileTime!=1, (Options&RowMajor)==0)
Понимание того, что вызывает утверждение
Вы предоставляете Eigen::VectorXi
в качестве ввода для write
.Eigen::VectorXi
на самом деле просто typedef для
Eigen::Matrix<int, Eigen::Dynamic, 1, Eigen::ColMajor, Eigen::Dynamic, 1>
Поэтому строка
Eigen::Matrix<T, Rows, Cols, Eigen::RowMajor, MaxRows, MaxCols> tmp = matrix;
в write
расширяется до
Eigen::Matrix<int, Eigen::Dynamic, 1, Eigen::RowMajor, Eigen::Dynamic, 1> tmp = matrix;
, что вызывает утверждение,поскольку матрица с MaxColsAtCompileTime==1
и MaxRowsAtCompileTime!=1
не должна быть RowMajor
.
Решите вашу проблему
Проблема в том, что даже если вы можете проверить,ваша входная матрица является векторной, мажорной или столбцовой, вы не можете объявить
Eigen::Matrix<T, Rows, Cols, Eigen::RowMajor, MaxRows, MaxCols>
, если это не разрешено делать во время компиляции (и это не из-за статического утверждения).
У вас есть следующие опции, чтобы ваш код работал:
1.if constexpr
(C ++ 17)
C ++ 17 предлагает способ определения во время компиляции, будет ли определенная условная ветвь взята или нет.Недостатком этого подхода (помимо требования к компилятору C ++ 17) является то, что вы можете проверять только константные выражения.
В конкретном примере это выглядит так:
template <class T, int Rows, int Cols, int Options, int MaxRows, int MaxCols>
std::vector<T> write(const Eigen::Matrix<T, Rows, Cols, Options, MaxRows, MaxCols>& matrix)
{
typedef Eigen::Matrix<T, Rows, Cols, Options, MaxRows, MaxCols> MatrixType;
std::vector<T> data(static_cast<size_t>(matrix.size()));
if constexpr (MatrixType::MaxRowsAtCompileTime == 1 ||
MatrixType::MaxColsAtCompileTime ==1 ||
(MatrixType::Options&Eigen::RowMajor) == Eigen::RowMajor) {
std::copy(matrix.data(), matrix.data() + matrix.size(), data.begin());
return data;
} else {
Eigen::Matrix<T, Rows, Cols, Eigen::RowMajor, MaxRows, MaxCols> tmp = matrix;
return write(tmp);
}
}
2.SFINAE
Вы можете отправить вызов на write
во время компиляции, используя SFINAE, используя std::enable_if
.В следующем примере используется слегка измененная версия исходного кода, но все должно быть ясно из контекста:
// matrix is either a vector or in row-major
template <typename Derived>
std::vector<typename Derived::Scalar> write(const Eigen::MatrixBase<Derived>& matrix,
typename std::enable_if<Derived::MaxRowsAtCompileTime == 1 ||
Derived::MaxColsAtCompileTime == 1 ||
(Derived::Options & Eigen::RowMajor) == Eigen::RowMajor,
Derived>::type* = 0)
{
std::vector<typename Derived::Scalar> data(
static_cast<size_t>(matrix.size()));
std::copy(matrix.derived().data(), matrix.derived().data() + matrix.size(),
data.begin());
return data;
}
// matrix is neither a vector nor in row-major
template <typename Derived>
std::vector<typename Derived::Scalar> write(const Eigen::MatrixBase<Derived>& matrix,
typename std::enable_if<Derived::MaxRowsAtCompileTime != 1 &&
Derived::MaxColsAtCompileTime != 1 &&
(Derived::Options & Eigen::RowMajor) == 0,
Derived>::type* = 0)
{
Eigen::Matrix<typename Derived::Scalar, Derived::RowsAtCompileTime,
Derived::ColsAtCompileTime, Eigen::RowMajor,
Derived::MaxRowsAtCompileTime, Derived::MaxColsAtCompileTime> tmp = matrix;
return write(tmp);
}
Это работает с использованием компилятора C ++ 11.
Другие варианты:специализируйте шаблон, но он станет еще длиннее, чем подход SFINAE.
Некоторые тестовые случаи:
Eigen::Matrix<int, 3, 3, Eigen::RowMajor> m;
m << 1, 2, 3,
1, 2, 3,
1, 2, 3;
std::vector<int> output = write(m);
for (const auto& element : output) {
std::cout << element << " ";
}
Вывод: 1 2 3 1 2 3 1 2 3
Eigen::Matrix<int, 3, 3, Eigen::ColMajor> m;
m << 1, 2, 3,
1, 2, 3,
1, 2, 3;
std::vector<int> output = write(m);
for (const auto& element : output) {
std::cout << element << " ";
}
Выход: 1 2 3 1 2 3 1 2 3
Eigen::VectorXi m = Eigen::VectorXi::LinSpaced(10, 0, 9);
std::vector<int> output = write(m);
for (const auto& element : output) {
std::cout << element << " ";
}
Выход: 0 1 2 3 4 5 6 7 89
Eigen::RowVectorXi m = Eigen::RowVectorXi::LinSpaced(10, 0, 9);
std::vector<int> output = write(m);
for (const auto& element : output) {
std::cout << element << " ";
}
Выход: 0 1 2 3 4 5 6 7 8 9