Почему списки инициализаторов недоступны при смене распределителя std::vector?
В моем проекте я изменил используемый тип точки от Eigen::Vector2f
до Eigen::Vector2d
и столкнулся с проблемой выравнивания.
Вот упрощенная версия кода:
#include <vector>
#include <Eigen/Eigen>
int main()
{
std::vector<Eigen::Vector2d> points = { {0,0}, {0,1} };
}
Я получаю следующую ошибку времени выполнения:
eigen3/Eigen/src/Core/DenseStorage.h:78: Eigen::internal::plain_array<double, 2, 0, 16>::plain_array() [T = double, Size = 2, MatrixOrArrayOptions = 0, Alignment = 16]: Assertion `(reinterpret_cast<size_t>(array) & 0xf) == 0 && "this assertion is explained here: " "http://eigen.tuxfamily.org/dox-devel/group__TopicUnalignedArrayAssert.html" " **** READ THIS WEB PAGE !!! ****"' failed.
В качестве предложения assert-сообщения я прочитал о требуемом выравнивании объектов Eigen с фиксированным размером. А также подраздел о STL Containers. И похоже, что у меня есть два варианта:
- используйте
Eigen::aligned_allocator
- или используйте макрос
EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION
.
Обе попытки не компилируются (протестированы с помощью GCC 4.8.3 и Clang 3.5), потому что компилятор не может правильно преобразовать список инициализаторов.
Здесь измененный код:
#include <vector>
#include <Eigen/Eigen>
#include <Eigen/StdVector>
// EIGEN_DEFINE_STL_VECTOR_SPECIALIZATION(Eigen::Vector2d)
int main()
{
std::vector<Eigen::Vector2d, Eigen::aligned_allocator<Eigen::Vector2d>> points = { {0,0}, {0,1} };
// std::vector<Eigen::Vector2d> points = { {0,0}, {0,1} };
}
Выход ошибки GCC:
error: could not convert ‘{{0, 0}, {0, 1}}’ from ‘<brace-enclosed initializer list>’ to ‘std::vector<Eigen::Matrix<double, 2, 1>, Eigen::aligned_allocator<Eigen::Matrix<double, 2, 1> > >’
Итак, мне интересно:
Ответы
Ответ 1
Изучив файл include Eigen/StdVector
(точнее, он находится в Eigen/src/StlSupport/StdVector.h
строка 68 версии 3.2.1), он кажется, что проблема возникает из частичной специализированной специализации std::vector
в этом заголовочном файле. Эта спецификация частичного шаблона заменяет STL vector
, как только вы используете Eigen::aligned_allocator
в качестве распределителя. И эта специализация, похоже, не имеет возможностей С++ 11.
Подробно, почему эта специализация необходима, кроме замены распределителя:
Перед С++ 11 функция изменения размера в std::vector
может принимать дополнительный параметр по значению для инициализации вновь созданных элементов. Согласно документации Eigen3 передача параметра по значению отбрасывает любые модификаторы выравнивания и не может использоваться с объектами Eigen с фиксированным размером (см. SIMD).
Edit:
После некоторого тестирования я понял, что реализация С++ 11 std::vector
не имеет указанной выше проблемы. Поэтому, чтобы решить проблему выравнивания, вы только должны заполнить Eigen::aligned_allocator
. Но не включать Eigen/StdVector
. Включение этого файла не позволит вам использовать реализацию С++ 11 std::vector
, поскольку этот заголовок определяет частичную специализацию с Eigen::aligned_allocator
как распределитель.