处理可选类成员的方法是什么?

问题描述 投票:0回答:1

处理大量数据(千兆字节)我使用数据数组的索引。由于访问数据可能会导致缓存效率低下,因此我想将数组中的一些数据与索引一起缓存,这可以显着提高通过索引的操作速度。

缓存数据量是编译时选择,应包括零量缓存数据。我有大量索引,因此在这种情况下,我不想像

std::array
那样为额外的“空”元素付费。

所以,我做了一个专门化的模板:

using index_t = unsigned int;
using lexem_t = unsigned int;

template <std::size_t t_arg_cache_line_size>
struct lexem_index_with_cache_t {
    index_t index;
    std::array<lexem_t, t_arg_cache_line_size> cache_line;

    constexpr std::size_t cache_line_size() const {
        return t_arg_cache_line_size;
    }
};

template<>
struct lexem_index_with_cache_t<0> {
    index_t index;
    static std::array<lexem_t, 0> cache_line;

    constexpr std::size_t cache_line_size() const {
        return 0;
    }
};

std::array<lexem_t, 0> lexem_index_with_cache_t<0>::cache_line;

问题是我在零大小的专业化中使用的这个“黑客”,它利用静态成员来提供对

cache_line
的正式访问,而它是空的并且实际上并不需要访问。这使我可以避免使用此模板的函数的专业化,如下所示:

using lexem_index_with_cache = lexem_index_with_cache_t<0>;

template <typename T>
class seq_forward_comparator_cached
{
    const std::vector<T>& vec;
public:
    seq_forward_comparator_cached(const std::vector<T>& vec) : vec(vec) { }

    bool operator() (const lexem_index_with_cache& idx1, const lexem_index_with_cache& idx2)
    {
        if (idx1.index == idx2.index) {
            return false;
        }

        const auto it1_cache_line = idx1.cache_line;  // This code wouldn’t compile in absence of static “hack”
        const auto it2_cache_line = idx2.cache_line;  // This code wouldn’t compile in absence of static “hack”

        auto res = std::lexicographical_compare_three_way(
            it1_cache_line.begin(), it1_cache_line.end(),
            it2_cache_line.begin(), it2_cache_line.end());

        if (res == std::strong_ordering::equal) {
            auto range1 = std::ranges::subrange(vec.begin() + idx1.index + idx1.cache_line_size(), vec.end());
            auto range2 = std::ranges::subrange(vec.begin() + idx2.index + idx2.cache_line_size(), vec.end());

            return std::ranges::lexicographical_compare(range1, range2);
        }

        return res == std::strong_ordering::less;
    }
};

当然,我可以实现该模板的另一个模板特化以实现零大小缓存,但这会导致代码重复,而且我有很多这样的函数,所以我不想特化所有这些。

现代 C++ 中避免这种

static
hack 和可能的代码重复的正确方法是什么?

我不确定,也许根据类型包含某种条件代码可能会有所帮助。

我想避免将对

cache_line
的访问包装到函数中,但如果这是唯一的情况,请提供有关方法的线索。

可编译的代码是这里

c++ templates generics
1个回答
0
投票

我添加了一个示例,其中包含在非模板代码中使用

if constexpr(...)
的技巧。

#include <array>

using data_type = int;

template<size_t _data_size>
class ExtendableIndex
{
public:
    constexpr static size_t data_size = _data_size;

    data_type& at(size_t idx) { return data[idx]; }

    size_t index;
    std::array<data_type, _data_size> data;
};

template<>
class ExtendableIndex<0>
{
public:
    constexpr static size_t data_size = 0;

    data_type& at(size_t idx);

    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]; // -> this fails to compile
            auto value = index.at(0); // -> but this slight workaround solves the issue, `at()` is not implemented and thats OK.
        }
    }

    template<size_t _data_size>
    void process_template(ExtendableIndex<_data_size>& index)
    {
        if constexpr (DefaultIndex::data_size > 0)
        {
            auto value = index.data[0]; // -> this compiles even if index.data doesn't exist when 'process' is a template
        }
    }

};

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);
}
© www.soinside.com 2019 - 2024. All rights reserved.