2016-03-31 29 views
5

Tôi muốn khái quát hóa các toán tử bitwise trong C++ mà không nghĩ rằng cấu trúc bên dưới là một mảng.Lập trình meta để tối ưu hóa thuật toán lưu trữ/thời gian chạy, C++

Như dụ ... nếu tôi muốn đại diện cho 86 bit tôi sẽ sử dụng một cấu trúc cấu trúc/lớp như:

typedef struct { 
uint64_t x[1]; 
uint16_t y[1]; 
uint8_t z[1]; 
} sampleStruct; 

Thay vào đó nếu tôi muốn phân bổ 160 bit Tôi sẽ sử dụng một cấu trúc như:

typedef struct { 
uint64_t x[2]; 
uint32_t y[1]; 
} sampleStruct; 

Tôi đoán một giải pháp nhỏ, nhưng không tối ưu cho việc lưu trữ sẽ là giả định tất cả các khối đều thống nhất và phân bổ tối thiểu nó bao gồm kích thước tôi đang thực hiện, tuy nhiên ngay cả đối với một vấn đề tập thể dục tôi thích cách tôi tiếp xúc.

Đối với tôi nó có vẻ rõ ràng rằng tôi nên sử dụng lập trình meta để giải quyết vấn đề, vì vậy tôi phải xác định đúng

template <int I> 
typedef sampleStruct { 
    //something 
} 

Tuy nhiên tôi không phải là một chuyên gia lớn trên C++ mẫu Lập trình meta vì vậy tôi muốn hiểu điều gì sẽ là cách tốt nhất để thực hiện các loại khác nhau của mẫu struct varing I. tôi biết làm thế nào để quyết định "cover" tốt nhất cho chiều dài của tôi nó sẽ là một cái gì đó như:

N64 = I/64; 
RemN = I%64; 
if(0 < RemN <= 8) { 
    add uint8_t var; 
} else if (8 < RemN <= 16) { 
    add uint16_t var; 
} else if (16 < RemN <= 24) { 
    add uint16_t var; 
    add uint8_t var; 
} else { 
    //Similarly handle the other cases from 24 < RemN < 64 
} 

tôi có thể làm gì để đạt được những gì Tôi muốn làm?

Tôi cũng đoán rằng các khối nổi bật sẽ cho phép đạt được hiệu suất tốt hơn một chút so với các triển khai có thể khác.

Hy vọng nó đủ rõ ràng ... (Giả sử C++ 11 hoặc các phiên bản mới hơn).

+7

Có vẻ như bạn muốn ['std :: bitset'] (http://en.cppreference.com/w/cpp/utility/bitset). – Daniel

+0

Tôi không biết nó tồn tại, nó hoạt động theo cách tôi mô tả? (lưu trữ tôi có nghĩa là). – user8469759

+0

có một cuộc nói chuyện về điều này: https://www.youtube.com/watch?v=ea5DiCg8HOY –

Trả lời

0

Có thể, nhưng có một số lượng hợp lý việc nhập liên quan. Vấn đề là C++ không cung cấp một cách để meta-lập trình bỏ qua một thành viên dữ liệu (xem ví dụ Conditional Inclusion/Exclusion of Data Members Inside Class Templates) vì vậy bạn phải chuyên về sự hiện diện hay vắng mặt của nó:

template<int N64, bool P32, bool P16, bool P8> 
struct sampleStructImpl; 

template<int I> 
using sampleStruct = sampleStructImpl<I/64, (I%64 >= 32), (I%32 >= 16), (I%16 >= 8)>; 

các chuyên ngành phần khác nhau (8 trong tổng số) sẽ trông như sau:

template<int N64> 
struct sampleStructImpl<N64, true, true, true> 
{ 
    std::uint64_t x[N64]; 
    std::uint32_t y; 
    std::uint16_t z; 
    std::uint8_t w; 
}; 

template<int N64> 
struct sampleStructImpl<N64, true, true, false> 
{ 
    std::uint64_t x[N64]; 
    std::uint32_t y; 
    std::uint16_t z; 
    // omit std::uint8_t w; 
}; 

// 6 more partial specializations... 

Ngoài ra, vì mảng zero-length là bất hợp pháp, nếu bạn muốn để có thể cho phép giá trị của I ít hơn 64 bạn sẽ phải chuyên về N64 là zero:

template<> 
struct sampleStructImpl<0, true, true, true> 
{ 
    // omit std::uint64_t x[0]; 
    std::uint32_t y; 
    std::uint16_t z; 
    std::uint8_t w; 
}; 

// 7 more specializations... 

Sẽ dễ dàng hơn rất nhiều khi sử dụng std::array<std::uint8_t, (I + 7)/8>, có thể với công cụ sửa đổi alignas để căn chỉnh 64 bit.

0

Nó sẽ không được dễ dàng hơn để sử dụng chỉ là một mảng của uint8_t, ví dụ:

template <int I> 
struct sampleStruct { 
    std::uint8_t v[(I % 8)? (I/8) + 1 : (I/8)]; 
}; 

Như bạn nói bit, tôi giả định rằng bạn không truy cập các thành viên cá nhân x,y,z, (đó là không rõ ràng từ câu hỏi làm thế nào bạn sẽ truy cập vào các bit cơ bản ..)

Có thể làm những gì bạn muốn là tốt, nhưng bạn phải sử dụng thừa kế, như sau:

template <int I> 
struct largeBlock { 
    std::uint64_t x[I]; 
}; 
template <> 
struct largeBlock<0> { 
}; 

template <int I> 
struct mediumBlock { 
    std::uint16_t y[I]; 
}; 
template <> 
struct mediumBlock<0> { 
}; 

template <int I> 
struct smallBlock { 
    std::uint8_t z[(I/8) + ((I % 8) ? 1 : 0) ]; 
}; 
template <> 
struct smallBlock<0> { 
}; 

template <int I> 
struct sampleStruct : largeBlock<I/64>, mediumBlock<(I % 64)/16>, smallBlock<(I % 16)> { 

}; 

Bây giờ hoạt động của bạn phải được thực hiện trong điều kiện của các cuộc gọi đến các đối tượng cơ sở ...

+0

Nó chắc chắn cho phép để đạt được những gì tôi muốn làm, về lưu trữ nó sẽ là yêu cầu tối thiểu. Tuy nhiên, sẽ có sự khác biệt về tính toán nếu bạn muốn thực hiện toán tử shift làm ví dụ. – user8469759

+0

Cách tiếp cận trên cũng hiệu quả cho việc lưu trữ (đó là những gì bạn đã làm sau), với thiết lập và đệm của bạn, cấu trúc của bạn sẽ khá lớn (ví dụ 16 byte cho 86 bit so với 11) - vì vậy để tối ưu hóa lưu trữ ở trên là khó để đánh bại .. Nếu bạn rephrase câu hỏi của bạn để xem xét chi phí hoạt động thời gian chạy, sau đó nó có thể quá .. – Nim

+0

Tại sao thực hiện của tôi cho 86 bit sẽ sử dụng 16 byte? Nó là 64 + 16 + 8, tức là 8 + 2 + 1 byte = 11 byte. Tôi đã nghĩ về cấu trúc rất lớn, Nếu bạn có một trường hợp ranh giới, chúng ta hãy nói 1024 bit tôi cần 16 biến uint64_t, so với 128 uint8_t, tôi làm một sự thay đổi phải 1 bit tôi sẽ chu kỳ trên 16 biến uint64_t chống lại 128 uint8_t, tôi nghĩ mọi điều tối ưu bạn thực hiện trên đoạn 8 bit sẽ giống nhau trong đoạn 64 bit trong trường hợp này. Một trường hợp tầm thường khác ... giả sử bạn muốn phân bổ 8 byte, trong trường hợp của bạn, bạn sẽ sử dụng 4 byte để làm điều đó, tôi có đúng không? Điều đó sẽ tốt hơn hay tương đương? – user8469759

Các vấn đề liên quan