使用运行时参数和编译时参数在类之间共享代码

时间:2019-06-16 21:12:29

标签: c++ templates code-reuse code-duplication

考虑一个模拟关联缓存的类:

template <size_t S, size_t L, size_t W>
class AssociativeCache {
  size_t which_set(size_t index) { return index % (L * W); }
  // ...
};

此处,关键高速缓存参数SLW是编译时非类型模板参数。

一个人也可以实现类似的类:

class AssociativeCacheDynamic {
  size_t S, L, L;
  size_t which_set(size_t index) { return index % (L * W); }
  // ...
};

这里,关键参数与其他情况相同,但存储为类的成员变量。

除了在动态情况下设置缓存参数值的构造函数之外,两个类的每个方法的实现也基本上相同,即源代码是逐字节相同的 1

如果我想同时使用这两个类,我该如何以最少的代码重复和尽可能少的粗俗宏或多个包含hack来实现它们?

如果解决方案允许您有一些不同之处,则奖励积分:例如,模板方法可能使用std::array存储,而动态方法可能使用std::vector


1 尽管编译后的代码通常会在根本上有所不同(因为该代码不是动态情况下的固定值专用)。

2 个答案:

答案 0 :(得分:2)

诀窍是提出基类来封装两种形式之间的差异,同时允许派生的模板类保留通用功能。像这样:

is_block_type_valid(header->_block_use)

模板库中的sub_function::input.encrypt()允许模板值用作代码中的常量,而不会占用任何内存。只要两个基数之间的大小变量bool class1::encrypt_step1() { bool *strBOOL_11_00 = (bool*)malloc(((strlen(this->fileStr)) + 1) * ((sizeof(bool)) * 8)); bool *strBOOL_10_01 = (bool*)malloc(((strlen(this->fileStr)) + 1) * ((sizeof(bool)) * 8)); bool *strBOOL_10_11 = (bool*)malloc(((strlen(this->fileStr)) + 1) * ((sizeof(bool)) * 8)); char *fileStrIt = this->fileStr; char *fileStrIt2 = ((this->fileStr) + 1); bool *next1100 = strBOOL_11_00; bool *next1001 = strBOOL_10_01; bool *next1011 = strBOOL_10_11; //translating to binary array iterating through pointers above one by one happens here //char->bin/encrypt/bin->char //ommited //reallocation to fit new encrypted and translated back to char that caused issues #ifdef ISSUE char *fileStr_temp = (char *)realloc(this->fileStr, ((next1011 - strBOOL_10_11) + (next1001 - strBOOL_10_01) + (next1100 - strBOOL_11_00) + 1)); if (!fileStr_temp) return 0; //original fileStr points at freed memory #endif #ifdef CORRECT char *fileStr_temp = (char *)realloc(this->fileStr, ((next1011 - strBOOL_10_11) + (next1001 - strBOOL_10_01) + (next1100 - strBOOL_11_00) + 1)); if (!fileStr_temp) return 0; else this->fileStr = fileStr_temp;//original fileStr points at new adress with reallocated data #endif free(strBOOL_11_00); strBOOL_11_00 = NULL; free(strBOOL_10_01); strBOOL_10_01 = NULL; free(strBOOL_10_11); strBOOL_10_11 = NULL; return 1; } bool class1::encrypt() { encrypt_step1(); ...//other steps (irrelevant) return 1; } #include <vector> template <size_t Sp, size_t Wp, size_t Lp> class AssociativeCacheTemplate { protected: static constexpr size_t S = Sp; static constexpr size_t W = Wp; static constexpr size_t L = Lp; AssociativeCacheTemplate() { } }; class AssociativeCacheDynamic { protected: size_t S; size_t W; size_t L; public: AssociativeCacheDynamic(size_t Sp, size_t Wp, size_t Lp): S(Sp), W(Wp), L(Lp) { } }; template <class T> class AssociativeCache: T { using T::L; using T::W; using T::S; public: using T::T; size_t which_set(size_t index) const { return index % (L * W); } }; int test() { AssociativeCache<AssociativeCacheTemplate<2, 16, 32>> t; AssociativeCache<AssociativeCacheDynamic> d(2, 16, 32); return t.which_set(3) * d.which_set(2); } static constexpr相同,主S类中的W语句就可以能够访问两个基类值。

L构造函数的using是使其编译所必需的。

答案 1 :(得分:0)

一种方法可能如下:

size_t which_set_impl(size_t index, size_t line_length, size_t ways_per_set)
{
    return index % (line_length * ways_per_set);
}

template <size_t S, size_t L, size_t W>
class AssociativeCache
{
    public:
        size_t which_set(size_t index) { return which_set_impl(index, L, W); }
};

class AssociativeCache2
{
    size_t size, line_length, ways_per_set;
    public:
        AssociativeCache2(size_t line_length_in, size_t ways_per_set_in) : line_length(line_length_in), ways_per_set(ways_per_set_in) {}
        size_t which_set(size_t index) { return which_set_impl(index, line_length, ways_per_set); }
};

int main(int argc, char** argv)
{
    AssociativeCache<10, 10, 10> MyCache1 = {};
    AssociativeCache2 MyCache2(10, 10);
    std::cout << "1: " << MyCache1.which_set(10) << " and 2: " << MyCache2.which_set(10) << std::endl;
    return 0;
}

或者,您可以使两个关联缓存都从暴露成员的基类扩展,例如:

    class BaseCache
    {
        virtual size_t GetLineLength() = 0;
        virtual size_t GetWaysPerSet() = 0;
        size_t which_set(size_t index) { return index % (this->GetLineLength() * this->GetWaysPerSet());
    }
    class AssociativeCacheFoo : BaseCache
    {
        ...
        size_t GetLineLength() const final override { return line_length; }
    }
    template <size_t S, size_t L, size_t W>
    class AssociativeCacheBar : BaseCache
    {
       ...
        size_t GetLineLength() const final override { return L; }
    }

上面的示例是伪代码,未经测试,不保证可以编译。

并通过将这些访问器公开或通过对两个访问器都使其成为朋友函数来将实现公开给助手函数。