如何统一访问可选存在的类成员?兼顾无冗余与透明性
问题:编译期可配置的带缓存索引结构优化方案
背景
处理GB级大数据时,我通过索引访问数据数组。由于直接访问数据会导致缓存效率低下,希望将部分数据与索引一起缓存,以此大幅提升基于索引的操作速度。缓存数据量为编译期可配置选项,包含缓存量为0的情况;同时因为需要创建大量索引,不希望像std::array那样在缓存量为0时支付额外的“空元素”开销。
现有方案1:虚拟静态std::array特化
我的首个思路是通过结构体特化,在缓存量为0的版本中引入虚拟静态std::array,保证data字段的访问透明性:
#include <array> using data_type = int; template<std::size_t _data_size> struct ExtendableIndex { std::size_t index; std::array<data_type, _data_size> data; }; template<> struct ExtendableIndex<0> { std::size_t index; constexpr static std::array<data_type, 0> data; // 虚拟静态对象保证data访问的透明性 }; constexpr std::array<data_type, 0> ExtendableIndex<0>::data; constexpr std::size_t cache_length = 0; // 可设置为任意缓存大小,包括0 using DefaultIndex = ExtendableIndex<cache_length>; void data_user(const DefaultIndex& index) { auto value = index.data.begin(); // 若无虚拟静态对象,ExtendableIndex<0>版本无法编译 } int main() { ExtendableIndex<cache_length> index_one; data_user(index_one); }
该方案运行正常,核心优势是所有处理data字段的算法无需区分缓存量是否为0,访问完全透明。
现有方案2:模板特化+访问方法/模板处理函数
Aedoro在回答相关问题时提供了另一种方案,通过类特化避免了虚拟静态成员,改用访问方法或模板化的处理函数解决问题:
#include <array> using data_type = int; template<std::size_t _data_size> class ExtendableIndex { public: constexpr static std::size_t data_size = _data_size; data_type& at(std::size_t idx) { return data[idx]; } std::size_t index; std::array<data_type, _data_size> data; }; template<> class ExtendableIndex<0> { public: constexpr static std::size_t data_size = 0; data_type& at(std::size_t idx); std::size_t index; }; using DefaultIndex = ExtendableIndex<0>; class DataUser { public: void process(DefaultIndex& index) { if constexpr (DefaultIndex::data_size > 0) { // auto value = index.data[0]; // 此写法无法编译 auto value = index.at(0); // 用at()方法规避问题,无需实现该方法 } } template<std::size_t _data_size> void process_template(ExtendableIndex<_data_size>& index) { if constexpr (DefaultIndex::data_size > 0) { auto value = index.data[0]; // 模板化处理函数下,即使data不存在也能编译 } } }; int main() { DataUser r; ExtendableIndex<0> index_zero; r.process(index_zero); r.process_template(index_zero); ExtendableIndex<1> index_one; r.process_template(index_one); }
该方案避免了虚拟静态对象的开销,但缺乏访问透明性:当处理逻辑规模大且频繁使用data时,需要编写大量if constexpr分支,还会影响依赖||和&&惰性求值的复杂条件。
疑问
是否存在第三种方案?能否像方案1一样实现data字段的透明访问,同时无需虚拟静态对象,且最好不用包装data字段的访问方法?
我知道可以对处理逻辑做功能分解,提取处理data的代码并制作带if constexpr的模板,但这种做法有时难度大,还容易导致代码重复,同时需要保留||和&&的惰性求值特性。
内容的提问来源于stack exchange,提问作者Damir Tenishev
相关产品推荐
相关产品推荐

