2012-02-23 40 views
7

Việc triển khai std::vector mà các phiên bản với Visual Studio 2010 và phiên bản cũ hơn có đặc trưng nổi tiếng: phương pháp resize có chữ ký sau (tuân thủ C++ 03) :Tự thực hiện STL tương thích STL :: vector

void resize(size_type new_size, value_type value); 

thay vì chữ ký C++ 11-compliant đó là được sử dụng bởi hầu hết các triển khai STL khác (như STL gcc hoặc STLport) rất lâu trước khi C++ 11:

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

các vấn đề với biến thể đầu tiên là, trong một số situa tions, nó sẽ không biên dịch nếu value_type có một đặc điểm kỹ thuật liên kết:

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

Đây là vấn đề wellknown không có cách giải quyết thỏa đáng ngoài việc sử dụng một thực hiện khác nhau của std::vector.

Tôi đang tìm kiếm một tốt bằng văn bản, được kiểm tra kỹ, khép kín và STL-tương thích thực hiện std::vector với một giấy phép MIT kiểu rằng tôi có thể thả vào dự án của tôi như là một container của sự lựa chọn cho việc sắp xếp loại.

Tôi xem xét giải nén nó từ STLport hoặc gcc's STL nhưng, hoàn toàn tuân thủ tiêu chuẩn, chúng đều lớn với nhiều phụ thuộc không tầm thường.

(Tôi sẽ hoàn toàn hài lòng với một thực hiện một tập hợp con hợp lý std::vector rằng sẽ chỉ hỗ trợ push_back, clear, capacity, size, reserve, resize, swap và mảng lập chỉ mục.)

Bất kỳ ý tưởng?

+0

Tôi không thấy phương thức '.resize()' làm cho khai báo 'std :: vector v;' thành không thành công. Việc khởi tạo một mẫu lớp không khởi tạo các phương thức của nó, chỉ các phương thức được sử dụng. (Tức là ctor và dtor mặc định trong trường hợp này). – MSalters

+0

Tôi đoán lỗi được phát ra trong quá trình phân tích cú pháp ... Hãy nhớ rằng chúng ta đang nói về một vấn đề cụ thể về trình biên dịch ở đây. –

Trả lời

8

Những người đứng sau thư viện Eigen dường như đã tìm được cách giải quyết tốt cho sự cố lưu trữ "loại được căn chỉnh quá mức" (as Stephan T. Lavavej call them) thành std::vector như được triển khai trong STL của Visual Studio.

thực hiện của họ dường như không cần thiết phức tạp (kiểm tra nguồn herehere) nhưng ý tưởng chính là để đóng gói các loại mà đi vào std::vector với một wrapper mỏng:

#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; 
} 

Về việc thực hiện trong Eigen, tôi phải thừa nhận tôi không hoàn toàn hiểu

  • lý do tại sao họ cần Eigen::aligned_allocator_indirection,
  • tại sao họ cần phải thực hiện một n ngoại lệ đối với các loại số học trong EIGEN_WORKAROUND_MSVC_STL_SUPPORT,
  • lý do tại sao họ cần phải xác định tất cả các nhà thầu và các nhà khai thác trong Eigen::workaround_msvc_stl_support,
  • hoặc tại sao họ cần phải xác định lại resize trong đặc tả từng phần của họ std::vector cho Eigen::aligned_allocator_indirection cấp phát ...

Đầu mối chào mừng. Vấn đề là, thủ thuật này hoạt động hoàn hảo (theo như tôi có thể nói) và tôi không thấy bất cứ điều gì sai trái với nó, ngoài việc có thể từ sự thiếu cân đối.

1

Tùy chọn đơn giản nhất (và tốt nhất, imho) sẽ là cung cấp chức năng miễn phí làm tiện ích mở rộng cho giao diện vector, hoạt động đúng. Các chức năng bạn cần phải thực hiện resize đều có sẵn từ giao diện công cộng của 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()); 
} 

Và đối với sự nhất quán cũng là phiên bản lập luận duy nhất:

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 
} 

Nếu bạn, tuy nhiên, chỉ muốn drop- trong vectơ mới và không bao giờ lo lắng về chức năng tự do hoặc thành viên, một tùy chọn khác là chỉ cần phân lớp 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()); 
    } 
}; 

Lưu ý rằng tôi cũng cung cấp phiên bản đối số duy nhất của resize, vì phiên bản hai đối số sẽ ẩn tất cả các phiên bản cấp cơ sở. Cũng lưu ý rằng tôi cần tiền tố tất cả các cuộc gọi hàm thành viên với this->, vì chúng phụ thuộc vào lớp cơ sở std::vector và như vậy trên các đối số mẫu.

+0

+1, mặc dù tôi sẽ lưu ý rằng phân lớp là đường biên ... –

+1

Phân lớp 'std :: vector' là một trong những cách tiếp cận đầu tiên của tôi, rất tiếc nó vẫn không biên dịch được vì cuối cùng,' std :: vector' vẫn được khởi tạo . –

+1

@ FrançoisBeaune: Ah, điều đó thật không may. :/Thử bình luận ra phiên bản 'std :: vector', hoặc đơn giản sửa chữ ký. : P FWIW, VS11 vẫn không khắc phục được sự cố này. – Xeo