2012-02-23 7 views
7

Реализация std::vector, которая поставляется с Visual Studio 2010 и более ранними версиями, имеет хорошо известную особенность: метод resize имеет следующую подпись (совместимый с C++ 03) :Автономная, STL-совместимая реализация std :: vector

void resize(size_type new_size, value_type value); 

вместо C++ 11-совместимом подпись, которая использовалась большинством других реализаций STL (например, STL GCC или STLport) задолго до того, C++ 11:

void resize(size_type new_size, const value_type& value); 

проблема с первым вариантом заключается в том, что в некоторых ситуациях ЦИИ, он не будет компилироваться, если value_type имеет спецификацию выравнивания:

struct __declspec(align(64)) S { ... }; 
std::vector<S> v; // error C2719: '_Val': formal parameter with __declspec(align('64')) won't be aligned 

Это wellknown проблема не удовлетворительного решения проблемы, кроме использования другой реализации std::vector.

Я ищу хорошо написанные, хорошо испытанные, самодостаточные и STL-совместимые реализации std::vector с лицензией MIT стиле, что я мог упасть в мой проект в качестве контейнера для выбора выровненных типы.

Я считал, что извлечение его из STLport или gcc STL, но, будучи полностью стандартным, они оба большие, с множеством нетривиальных зависимостей.

(я был бы совершенно счастлив с реализацией разумного подмножества std::vector, которые поддерживают только push_back, clear, capacity, size, reserve, resize, swap и индексации массива.)

Любые идеи?

+0

Я не вижу, как метод '.resize()' вызывает 'std :: vector v;' Объявление сбой. Создание экземпляра шаблона класса не создает его методы, а только те, которые используются. (I.e. по умолчанию ctor и dtor в этом случае). – MSalters

+0

Я предполагаю, что ошибка возникает во время разбора ... Имейте в виду, что мы говорим о конкретной проблеме, связанной с компилятором. –

ответ

8

Ребята позади Eigen библиотеки, кажется, нашли хороший способ обхода проблемы хранения «чрезмерно выровненные типов» (as Stephan T. Lavavej call them) в std::vector как это реализовано в STL в Visual Studio.

Их реализация кажется ненужным сложным (проверить источники here и here), но основная идея заключается в том, чтобы инкапсулировать тип, который входит в std::vector с тонкой оболочкой:

#include <vector> 

template <typename T> 
struct wrapper : public T 
{ 
    wrapper() {} 
    wrapper(const T& rhs) : T(rhs) {} 
}; 

struct __declspec(align(64)) S 
{ 
    float x, y, z, w; 
}; 

int main() 
{ 
    std::vector< wrapper<S> > v; // OK, no C2719 error 
    return 0; 
} 

О реализации в Эйгене, я должен признать, что я не совсем понимаю,

  • почему они нуждаются в Eigen::aligned_allocator_indirection,
  • , почему они должны сделать п исключение для арифметических типов в EIGEN_WORKAROUND_MSVC_STL_SUPPORT,
  • почему они должны определить все эти конструктор и оператор в Eigen::workaround_msvc_stl_support,
  • или почему они должны пересмотреть resize в их частичной специализации std::vector для Eigen::aligned_allocator_indirection распределителя ...

Подсказки приветствуются. Дело в том, что этот трюк работает отлично (насколько я могу судить), и я не вижу в этом ничего плохого, кроме, может быть, от незначительной неэффективности.

1

Самый простой (и лучший, imho) вариант должен был бы предоставить бесплатную функцию в качестве расширения для интерфейса vector, что делает правильную вещь. Функции, которые необходимо реализовать resize все имеющиеся от общедоступного интерфейса std::vector:

#include <vector> 

template<class T, class Alloc> 
void resize(std::vector<T, Alloc>& v, 
    typename std::vector<T, Alloc>::size_type new_size, T const& val) 
{ 
    if (v.size() < new_size) 
     v.insert(v.end(), new_size - v.size(), val); 
    else if (new_size < v.size()) 
     v.erase(v.begin() + new_size, v.end()); 
} 

И для согласованности также единой версии аргумента:

template<class T, class Alloc> 
void resize(std::vector<T, Alloc>& v, 
    typename std::vector<T, Alloc>::size_type new_size) 
{ 
    v.resize(new_size); // simply forward 
} 

Если вы, тем не менее, просто хочет раскрывающийся в новом векторе и никогда не беспокоиться о свободном или члена функции, другой вариант просто подкласс std::vector:

#include <vector> 
#include <memory> 

template<class T, class Alloc = std::allocator<T>> 
class myvector 
    : public std::vector<T, Alloc> 
{ 
    typedef std::vector<T, Alloc> base; 
public: 
    typedef typename base::size_type size_type; 

    void resize(size_type new_size){ 
    base::resize(new_size); 
    } 

    void resize(size_type new_size, T const& val){ 
    if (this->size() < new_size) 
     this->insert(this->end(), new_size - this->size(), val); 
    else if (new_size < this->size()) 
     this->erase(this->begin() + new_size, this->end()); 
    } 
}; 

Обратите внимание, что я также предоставил версию единственного аргумента resize, поскольку две версии аргументов скроют все версии базового класса. Также обратите внимание, что мне нужно было префикс всех вызовов функций-членов с помощью this->, так как они зависят от базового класса std::vector и как такового в аргументах шаблона.

+0

+1, хотя я бы заметил, что подклассификация является граничной ... –

+1

Подкласс 'std :: vector' был одним из моих первых подходов, к сожалению, он все еще не скомпилирован, потому что в конце концов' std :: vector' все еще получает экземпляр , –

+1

@ FrançoisBeaune: Ах, это относительно неудачно. :/Попробуйте прокомментировать версию 'std :: vector' или просто исправьте подпись. : P FWIW, VS11 по-прежнему не исправляет эту проблему. – Xeo