非 class 模板中数据成员 std::array 的编译时间大小 (C++14)

Compile time size of data member std::array in non-class template (C++14)

编译时检查std::array数据成员的(编译时)大小

我需要静态断言 std::array 类型的非 constexpr 数据成员的编译时大小,比如 arr_ 非模板 class 等于给定的(外部提供的)常量。静态断言将从 class 内部完成,这意味着 arr_ 是可访问的,但我不能依赖任何存储的常量(也不是非类型模板参数)来确定其大小。也就是说,断言需要完全依赖于 arr_ 数据成员的“一些检查”。

如果 constexpr std::array<>::size()/std::array<>::max_size() 是静态成员函数(decltype(arr_)::size()/decltype(arr_)::max_size())而不是非静态成员函数。

我有一个工作方法,在 arr_ 成员的数据成员指针上使用函数模板参数推导,但我想知道是否有 easier/neater 方法。

#include <array>
#include <cstddef>

// Defined/provided from elsewhere.
constexpr std::size_t kArraySize = 12U;
constexpr std::size_t kAnotherArraySize = 12U;

template <typename T, typename U, std::size_t N>
constexpr std::size_t size_of_data_member_array(std::array<T, N> U::*) {
    return N;
}

class Foo {
    std::array<int, kArraySize> arr_;
    static_assert(size_of_data_member_array(&Foo::arr_) == kAnotherArraySize, "");
};

int main() {}

您可以在静态断言中创建具有相同类型 Foo::arr_ 的数组实例:

class Foo {
    std::array<int, kArraySize> arr_;
    static_assert(decltype(arr_){}.size() == kAnotherArraySize, "");
};

参见this example

注意:仅当数组值类型是 POD 或具有默认的 constexpr 构造函数时才有效。

只是为了提供另一种选择,您可以对模板变量进行部分特化。

#include <array>
#include <cstddef>

// Defined/provided from elsewhere.
constexpr std::size_t kArraySize = 12U;
constexpr std::size_t kAnotherArraySize = 12U;

template <typename T>
constexpr std::size_t array_size = 0;

template <typename T, std::size_t N>
constexpr std::size_t array_size<std::array<T, N>> = N;

class Foo {
    std::array<int, kArraySize> arr_;
    static_assert(array_size<decltype(arr_)> == kAnotherArraySize, "");
};

int main() {}

使用 SFINAE 提供另一种选择:

#include <type_traits>
#include <array>

template <typename T>
constexpr bool is_array_v = false;

template <typename T, size_t N>
constexpr bool is_array_v<std::array<T, N>> = true;

template <typename Array, std::enable_if_t<is_array_v<Array>, int> = 0>
constexpr size_t array_size_v = std::tuple_size<Array>::value;

static_assert(array_size_v<std::array<int, 5>> == 5); // OK
static_assert(array_size_v<int> == 5);                // Won't compile

与其他提案不同,这会在编译时捕获对 array_size_v 的误用,因此输入 int 和其他非 std::array 的类型将不起作用。

该标准在名称 tuple_size 下提供了 array::size 的静态版本:

#include <array>
#include <tuple> // for std::tuple_size_v

static_assert(std::tuple_size<decltype(arr_)>::value == kAnotherArraySize, "");
static_assert(std::tuple_size_v<decltype(arr_)> == kAnotherArraySize); // C++17