Почему списки инициализаторов недоступны при изменении распределителя 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.

Как было предложено в утверждении-сообщении, я прочитал о необходимом выравнивании векторизуемых объектов Eigen фиксированного размера. А также подраздел о контейнерах STL. И похоже, что у меня есть два варианта:

  1. используйте Eigen::aligned_allocator
  2. или используйте макрос 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> > >’

Поэтому мне интересно:

  • Почему списки инициализаторов недоступны при изменении распределителя std::vector?

    • Is this because of alignment?
    • Можно ли как-то выровнять список инициализаторов?
  • Почему версия специализации не работает?

    • Are these lacking the initializer list feature?

person mic    schedule 19.06.2014    source источник


Ответы (1)


Изучив включаемый файл Eigen/StdVector (точнее, он находится в Eigen/src/StlSupport/StdVector.h строка 68 версии 3.2.1), похоже, проблема возникает из-за частичной специализации шаблона std::vector в этом заголовочном файле. Эта специализация частичного шаблона заменяет STL vector, как только вы используете Eigen::aligned_allocator в качестве распределителя. И этой специализации, похоже, не хватает возможностей C++11.

Подробно, почему эта специализация необходима, кроме замены распределителя: до C++11 функция изменения размера из std::vector может принимать дополнительный параметр по значению для инициализации вновь созданных элементов. Согласно документации Eigen3 передача параметра по значению отбрасывает любые модификаторы выравнивания и не может использоваться с векторизуемые собственные объекты фиксированного размера (см. SIMD).

Редактировать: После еще нескольких тестов я понял, что реализация std::vector на C++11 не имеет вышеуказанной проблемы. Таким образом, чтобы решить проблему с выравниванием, вам только нужно заполнить поле Eigen::aligned_allocator. Но не включайте Eigen/StdVector. Включение этого файла не позволит вам использовать реализацию std::vector в C++11, поскольку этот заголовок определяет частичную специализацию с Eigen::aligned_allocator в качестве распределителя.

person mic    schedule 21.06.2014