我試圖在連續的記憶體塊中跟蹤不同大小的段。段的大小和順序在編譯時是已知的,所以我想在編譯時計算它們在塊內的偏移量。我希望能夠遍歷這些段的大小和偏移量,但我也希望能夠在需要時按名稱呼叫特定的段。如果在整個專案構建程序中段的大小、順序或數量發生變化,我希望盡量減少冗余,以便調整/重組的部分更少。
例如,我有一個記憶體塊,最多可以包含 12 個物件實體(所有型別都相同)。為了這個例子,假設它有 12 個三角形實體,每個三角形實體由 3 個 2D 坐標組成(總共 6 個浮點數)。在這種情況下,每段將代表一些幾何形狀,第一段可能只是一個三角形(實體數 1),第二段是多面體(讓保持 10 個三角形實體),第三段是正方形(實體數 2)。幾何圖形將按照它們在記憶體塊中的排列順序繪制(第一個/三角形、第二個/多面體和第三個/正方形段)。第一個線段(三角形)的偏移量為 0。第二個線段(多面體)的偏移量為 1(0 三角形的大小)。第三段的偏移量,正方形,將是 11(0 三角形的大小 多面體的大小)。現在,如果我想繪制所有幾何圖形,能夠遍歷大小陣列和偏移陣列以告訴 gpu 幾何圖形的開始位置(偏移量)以及持續多長時間(大小)會很好。另一方面,如果我想將多面體幾何體向左移動,那么如果我決定更改順序(例如 make多面體是要繪制的第一個幾何體)我可以重新排列陣容,但不必記住將所有對多面體偏移和大小的呼叫更改為其新索引。現在,如果我想繪制所有幾何圖形,能夠遍歷大小陣列和偏移陣列以告訴 gpu 幾何圖形的開始位置(偏移量)以及持續多長時間(大小)會很好。另一方面,如果我想將多面體幾何體向左移動,那么如果我決定更改順序(例如 make多面體是要繪制的第一個幾何體)我可以重新排列陣容,但不必記住將所有對多面體偏移和大小的呼叫更改為其新索引。現在,如果我想繪制所有幾何圖形,能夠遍歷大小陣列和偏移陣列以告訴 gpu 幾何圖形的開始位置(偏移量)以及持續多長時間(大小)會很好。另一方面,如果我想將多面體幾何體向左移動,那么如果我決定更改順序(例如 make多面體是要繪制的第一個幾何體)我可以重新排列陣容,但不必記住將所有對多面體偏移和大小的呼叫更改為其新索引。
我最初的想法是用一個列舉來表示段的順序(三角形,然后是多面體,然后是正方形)。然后,我可以在具有命名整數變數的結構之間建立聯合,這些變數表示我可以按名稱呼叫的單個段大小和我可以迭代的整數陣列。結果如下:
struct Memory {
struct Enum {
enum {triangleSegment, polyhedronSegment, squareSegment, count};
};
union SegmentSizes{
struct Names {
constexpr Names() = default;
const uint8_t triangleSegment = 1, polyhedronSegment = 10, squareSegment = 2;
};
Names names;
std::array<uint8_t, Enum::count> arr;
};
static constexpr SegmentSizes sizes{ SegmentSizes::Names() };
};
int main() {
std::cout << std::to_string(Memory::sizes.names.triangleSegment) << std::endl;
std::cout << std::to_string(Memory::sizes.arr[1]) << std::endl;
}
以上作業......取決于編譯器。MSVC 編譯得很好,但 gcc 似乎不喜歡這static constexpr SegmentSizes sizes{ SegmentSizes::Names() };條線。
我在編譯時計算偏移量的想法是使用 constexpr 函式構造一個偏移量陣列,然后用結果填充另一個靜態 constexpr 聯合:
//Declared within Memory, below static constexpr SegmentSizes sizes
struct SegmentOffsets {
static constexpr std::array<uint16_t, Enum::count> arr() {
std::array<uint16_t, Enum::count> a{};
uint16_t currOffset = 0;
for (uint8_t i = 0; i < Enum::count; i) {
a[i] = currOffset;
currOffset = sizes.arr[i];
}
return a;
}
struct Names {
const uint16_t triangleSegment, polyhedronSegment, squareSegment;
};
static constexpr Names names{ *reinterpret_cast<Names*>(arr().data()) };
};
但出于某種原因,我不明白編譯器聲稱該arr()函式不是編譯時常量。
Beyond trying to fine tune my understanding of constexpr and compile time constants a little more I am also wondering if there is simply an easier way in general to accomplish the same goal. I'm open to all suggestions.
For completeness below is the entire code snippet:
#include <array>
#include <iostream>
#include <string>
struct Memory {
struct Enum {
enum {triangleSegment, polyhedronSegment, squareSegment, count};
};
union SegmentSizes{
struct Names {
constexpr Names() = default;
const uint8_t triangleSegment = 1, polyhedronSegment = 10, squareSegment = 2;
};
Names names;
std::array<uint8_t, Enum::count> arr;
};
static constexpr SegmentSizes sizes{ SegmentSizes::Names() };
struct SegmentOffsets {
static constexpr std::array<uint16_t, Enum::count> arr() {
std::array<uint16_t, Enum::count> a{};
uint16_t currOffset = 0;
for (uint8_t i = 0; i < Enum::count; i) {
a[i] = currOffset;
currOffset = sizes.arr[i];
}
return a;
}
struct Names {
const uint16_t triangleSegment, polyhedronSegment, squareSegment;
};
static constexpr Names names{ *reinterpret_cast<Names*>(arr().data()) };
};
};
int main() {
std::cout << std::to_string(Memory::sizes.names.triangleSegment) << std::endl;
std::cout << std::to_string(Memory::sizes.arr[1]) << std::endl;
}
uj5u.com熱心網友回復:
arr() 函式不是編譯時常量。
從聯合讀取只能在聯合的活動欄位上完成,否則是未定義行為。arr()總是被破壞,它只是在編譯期間執行時被捕獲。
否則,通過用簡單的函式呼叫替換命名訪問,可以使整個方法變得更加簡單:
#include <array>
#include <iostream>
#include <string>
template<std::size_t N>
constexpr std::array<uint16_t, N> calc_offsets(const std::array<uint8_t, N>& sizes) {
std::array<uint16_t, N> result;
uint16_t accum = 0;
std::size_t i = 0;
for(const auto & size : sizes) {
result[i ] = accum;
accum = size;
}
return result;
}
struct Memory {
enum Segment {firstGroup, secondGroup, thirdGroup, segment_count};
static constexpr std::array<uint8_t, (std::size_t)segment_count> segment_sizes = {1, 10 , 1};
static constexpr std::array<uint16_t, (std::size_t)segment_count> segment_offsets = calc_offsets(segment_sizes);
static constexpr uint8_t size(Segment s) {return segment_sizes[(std::size_t)s];}
static constexpr uint16_t offset(Segment s) {return segment_offsets[(std::size_t)s];}
};
int main() {
std::cout << std::to_string(Memory::size(Memory::firstGroup)) << std::endl;
std::cout << std::to_string(Memory::segment_offsets[1]) << std::endl;
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/yidong/347350.html
標籤:c arrays union constexpr compile-time-constant
