如何静态断言 std::array 成员的大小
Posted
技术标签:
【中文标题】如何静态断言 std::array 成员的大小【英文标题】:How to static_assert the size of a std::array member 【发布时间】:2016-02-04 22:28:34 【问题描述】:我想明确说明成员变量的数组大小限制,以防止其他人意外做出愚蠢的更改。以下天真的尝试将无法编译:
struct Foo
std::array< int, 1024 > some_array;
static_assert( (some_array.size() % 256) == 0, "Size must be multiple of 256" );
//^ (clang) error: invalid use of non-static data member 'some_array'
;
即使std::array::size
是一个constexpr,我也不能像那样直接使用static_assert
,因为函数和我的成员变量都不是静态的。
我想出的解决方案是使用decltype
(因为我不想typedef数组)如下:
static_assert( (decltype(some_array)().size() % 256) == 0, "Size must be multiple of 256" );
这看起来像是在默认构造一个 rvalue,我不认为它是一个 constexpr。
为什么会这样?
有没有更简洁的方法来实现静态断言?
【问题讨论】:
你的功能对我来说很好,先生 o.o,在 vusal 工作室。(declval<decltype(some_array)>().size() % 256) == 0
不起作用?
【参考方案1】:
因为函数和我的成员变量都不是静态的。
没错。问题是静态断言不能引用非静态成员,因为some_array.size()
等价于this->some_array.size()
,并且在类范围内没有this
指针(仅在函数声明符和默认成员初始化程序内部)。
但是,说 decltype(array_size)
是可以的,因为这实际上并不是在尝试引用对象 array_size
或调用其成员函数,它只是查询在类中声明的名称的类型。
这看起来像是在默认构造一个右值,我不认为它是一个 constexpr。
array<int, N>
是文字类型,因此可以用常量表达式构造。您构造右值的事实并不重要,您可以构造文字类型并在常量表达式中对其调用 constexpr 成员函数。
不能在那里使用像array<std::string, N>
这样的东西,因为std::string
不是文字类型,所以array<string, N>
也不是。
有没有更简洁的方法来实现静态断言?
标准特征std::tuple_size
专门用于std::array
,因此您可以这样做:
static_assert( std::tuple_size<decltype(some_array)>::value % 256) == 0,
"Size must be multiple of 256" );
【讨论】:
不幸的是,当您从std::array
继承并希望对派生类使用结构绑定时,这并不能解决问题。在这种情况下,您需要为派生类定义部分模板特化,因此不能依赖std::tuple_size
。【参考方案2】:
std::array::size
是 constexpr
并且应该与 static_assert
一起使用,但是它在这个特定的上下文中(即在类定义中)不起作用,因为 some_array
是一个非静态成员变量。
对于这个特定的上下文,您可以使用自制的类型特征在编译时获取大小,如下所示:
template<typename>
struct array_size;
template<typename T, std::size_t N>
struct array_size<std::array<T, N>>
static const std::size_t size = N;
;
而static_assert
为:
static_assert(array_size<decltype(some_array)>::size % 256) == 0, "Size must be multiple of 256" );
Live Demo
【讨论】:
看起来你混淆了类型和值元函数:) 这就是我所期望的std::array
的实现方式......为什么不能直接访问模板的大小值?但事实并非如此。虽然这是一个很酷的解决方案,但我不确定它是否真的“更干净”,因为它似乎需要更多的框架。
using size = N;
无效,这将声明 typedef,但 N
不是类型。您可能希望 template<typename T, std::size_t N> struct array_size<std::array<T, N>> : std::integral_constant<std::size_t, N> ;
然后将 array_size<A>::value
定义为大小。但是,标准库中已经存在 std::tuple_size
与 std::array
一起使用
@paddy,为了与其他容器保持一致,数组大小是成员函数,而不是静态常量。适用于 STL 风格容器的通用代码可以依赖begin()
、end()
、size()
等。以上是关于如何静态断言 std::array 成员的大小的主要内容,如果未能解决你的问题,请参考以下文章