如何在编译时检查查找表是否具有正确的大小?

时间:2016-11-24 08:41:05

标签: c++

我对lookup table的硬编码值。所需数量的元素来自包含的文件,该文件可能在将来的某个时刻发生变化。所以我想确保在编译时我指定的元素数量确实与所需数量相匹配。

看一下这段代码:

#include <array>

// Assume this comes from some included file
constexpr size_t elementCount = 5;

int main() {
    // This works.
    const std::array<int, elementCount> lookup { 2, 4, 6, 8, 10 };

    // But so does this.
    const std::array<int, elementCount> lookup2 { 2, 4, 6 };

    return 0;
}

std::array似乎非常适合查找表,因为它的大小在编译时是固定的。但是,我无法确保使用正确数量的元素初始化它。由于aggregate initialization,即使我指定的元素太少,该示例也会很好地编译。

我提出了以下解决方法,但感觉非常难看:

#include <array>

template<class T> std::array<T, 1> makeArray(T e1) {
    return { e1 };
}

template<class T> std::array<T, 2> makeArray(T e1, T e2) {
    return { e1, e2 };
}

template<class T> std::array<T, 3> makeArray(T e1, T e2, T e3) {
    return { e1, e2, e3 };
}

template<class T> std::array<T, 4> makeArray(T e1, T e2, T e3, T e4) {
    return { e1, e2, e3, e4 };
}

template<class T> std::array<T, 5> makeArray(T e1, T e2, T e3, T e4, T e5) {
    return { e1, e2, e3, e4, e5 };
}

// ... and so on; these functions would live in some utility header file.

// Assume this comes from some included file
constexpr size_t elementCount = 5;

int main() {
    // This works.
    const std::array<int, elementCount> lookup = makeArray(2, 4, 6, 8, 10);

    // This doesn't. :-)
    const std::array<int, elementCount> lookup2 = makeArray(2, 4, 6);

    return 0;
}

所以问题是:是否有一种优雅的方法可以确保在编译时我为查找表指定正确的元素数量?硬编码?请注意数据类型不需要std::array;任何以常量时间索引的序列容器都可以。

2 个答案:

答案 0 :(得分:6)

您可以对make_array(类似于图书馆基础知识TS中的make_array)进行模板化处理:

template<typename T, typename... Params>
std::array<T, sizeof...(Params)> make_array(Params&&... ps) {
    return { std::forward<Params>(ps)... };
}

现在,只需创建你的数组:

int main() {
    // This works.
    const auto lookup = makeArray<int>(2, 4, 6, 8, 10);
    static_assert(lookup.size() == elementCount, "");


    // This doesn't. :-)
    const auto lookup2 = makeArray<int>(2, 4, 6);
    static_assert(lookup2.size() == elementCount, ""); // error
}

如果需要,可以将断言移动到make_array函数(或为其创建一个包装器),但随后可能会更改名称:

template<typename T, typename... Params>
std::array<T, sizeof...(Params)> make_lookup_array(Params&&... ps) {
    static_assert(sizeof...(Params) == elementCount, "must be equal!");
    return { std::forward<Params>(ps)... };
}

答案 1 :(得分:1)

您可以使用可变参数模板

#include <array>

// Assume this comes from some included file
constexpr size_t elementCount = 5;

template<class first, class ... T>
std::array<first, 1 + sizeof...(T)> makeArray(first e1, T ... rest) {
    static_assert(1 + sizeof...(T) == elementCount, "Must match elementCount");
    return {  std::forward<first>(e1), std::forward<T>(rest) ...};
}

int main() {
    // This works.
    const auto lookup = makeArray(2, 4, 6, 8, 10);

    // This doesn't. :-)
    const auto lookup2 = makeArray(2, 4, 6);
}

您可以尝试here

编辑:

class firstclass ... T的使用允许编译器自动推断元素的类型。也就是说,makeArray的第一个参数的类型定义了std::array::value_type