[英]size() of std::array pointer in constexpr context
Let's say I have a function like: 假设我的功能如下:
int test(std::array<char, 8>* data) {
char buffer[data->size() * 2];
[... some code ...]
}
clearly the size of the buffer can be evaluated at compile time: data has a constexpr
size of 8 elements, 8 * 2 = 16 bytes. 显然,可以在编译时评估缓冲区的大小:数据的
constexpr
大小为8个元素,8 * 2 = 16个字节。
However, when compiling with -Wall
, -pedantic
and -std=c++11
I get the infamous error: 但是,当使用
-Wall
, -pedantic
和-std=c++11
编译时,我得到了臭名昭着的错误:
warning: variable length arrays are a C99 feature [-Wvla-extension]
警告:可变长度数组是C99功能[-Wvla-extension]
which I believe makes sense: array::size()
is constexpr
, but it is still a method, and in the function above we still have to dereference a pointer, which is not constexpr
. 我认为有道理:
array::size()
是constexpr
,但它仍然是一个方法,在上面的函数中我们仍然需要取消引用一个指针,这不是constexpr
。
If I try something like: 如果我尝试类似的东西:
int test(std::array<char, 8>& data) {
char buffer[data.size() * 2];
[...]
}
gcc
(tried version 5.2.0) seems happy: there is no warning. gcc
(试用版5.2.0)似乎很高兴:没有警告。
But with clang++
(3.5.1) I still get a warning complaining about variable length arrays. 但是对于
clang++
(3.5.1),我仍然会收到一个抱怨可变长度数组的警告。
In my case, I can't easily change the signature of test
, it has to take a pointer. 在我的情况下,我不能轻易改变
test
的签名,它必须采取指针。 So... a few questions: 那么......几个问题:
What is the best / most standard way to get the size of a std::array
pointer in constexpr context? 在constexpr上下文中获取
std::array
指针大小的最佳/最标准方法是什么?
Is the difference in behavior with pointers vs references expected? 预期指针与引用的行为有何不同? Which compiler is right about the warning,
gcc
or clang
? 哪个编译器对警告,
gcc
或clang
是正确的?
I do not know about 2. 我不知道2。
But for 1, we can do this: 但对于1,我们可以这样做:
template<class T, size_t N>
constexpr std::integral_constant<size_t, N> array_size( std::array<T, N> const& ) {
return {};
}
then: 然后:
void test(std::array<char, 8>* data) {
using size=decltype(array_size(*data));
char buffer[size{}];
(void)buffer;
// [... some code ...]
}
alternatively: 或者:
template<class T, class U, size_t N>
std::array<T,N> same_sized_array( std::array< U, N > const& ) {
return {};
}
void test(std::array<char, 8>* data) {
auto buffer = same_sized_array<char>(*data);
(void)buffer;
// [... some code ...]
}
finally, a C++14 cleanup: 最后,一个C ++ 14清理:
template<class A>
constexpr const decltype(array_size( std::declval<A>() )) array_size_v = {};
void test3(std::array<char, 8>* data) {
char buffer[array_size_v<decltype(*data)>];
(void)buffer;
// [... some code ...]
}
Live example . 实例 。
The good old C way would be a define, but C++ has const int
or for C++11 constexpr
. 好的旧C方式是定义,但C ++有
const int
或C ++ 11 constexpr
。 So if you want the compiler to be aware that the size of the array is a compile time constant, the most portable(*) way would be to make it a const
or constexpr
: 因此,如果您希望编译器知道数组的大小是编译时常量,那么最便携(*)的方法是使它成为
const
或constexpr
:
#include <iostream>
#include <array>
const size_t sz = 8; // constexpr size_t sz for c++11
int test(std::array<char, sz>* data) {
char buffer[sz * 2];
buffer[0] = 0;
return 0;
}
int main()
{
std::array<char, sz> arr = { { 48,49,50,51,52,53,54,55 } };
int cr = test(&arr);
std::cout << cr << std::endl;
return 0;
}
It compiles without a warning, even with -Wall -pedantic
under Clang 3.4.1 它在没有警告的情况下编译,即使在Clang 3.4.1下使用
-Wall -pedantic
For the second question, I cannot imagine why gcc make that difference between pointers and refs here. 对于第二个问题,我无法想象为什么gcc在这里指出和引用之间的区别。 Either it can determine that
size()
method on an std::array
whose size is a constant is a constant expression - and it should allow both - or it cannot - and it should emit same warning on both. 它可以确定大小为常量的
std::array
上的size()
方法是一个常量表达式 - 它应该允许两者 - 或者它不能 - 并且它应该在两者上发出相同的警告。 But it does not only concern the compiler, but also the standard library implementation. 但它不仅涉及编译器,还涉及标准库实现。
The real problem is that pre-C++11 std::array was not part of the standard library, and constexpr
is also defined only from C++11 on. 真正的问题是pre-C ++ 11 std :: array不是标准库的一部分,
constexpr
也是仅从C ++ 11开始定义的。 So in pre-C++11 mode, both compiler process std::array as an extension, but there is no way for the size
method to declare its return value to be a constant expr. 所以在pre-C ++ 11模式下,两个编译器都将std :: array作为扩展进程,但是
size
方法没有办法将其返回值声明为常量expr。 This explains why Clang (and gcc facing a pointer) emits the warning. 这解释了为什么Clang(以及面向指针的gcc)会发出警告。
But if you compile original code in c++11 mode ( -std=c++11
) you should have no warning, because the standard requires size()
method on a std::array
to be a constexpr
. 但是如果你在c ++ 11模式下编译原始代码(
-std=c++11
),你应该没有警告,因为标准要求std::array
上的size()
方法是constexpr
。
(*) The question is about best / most standard ; (*)问题是关于最佳/最标准的 ; I cannot say what is best way, and I cannot define most standard either, so I stick to what I would use if I wanted to avoid portability problems on non C++11 compilers.
我不能说什么是最好的方式,我也无法定义大多数标准 ,所以如果我想避免非C ++ 11编译器上的可移植性问题,我会坚持使用。
What about using std::tuple_size
on the decltype of your parameter ? 如何在参数的decltype上使用
std::tuple_size
?
void test(std::array<char, 8>* data) {
using data_type = std::remove_pointer<decltype(data)>::type;
char buffer[std::tuple_size<data_type>::value * 2];
static_assert(sizeof buffer == 16, "Ouch");
// [... some code ...]
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.