[英]size() of std::array pointer in constexpr context
假設我的功能如下:
int test(std::array<char, 8>* data) {
char buffer[data->size() * 2];
[... some code ...]
}
顯然,可以在編譯時評估緩沖區的大小:數據的constexpr
大小為8個元素,8 * 2 = 16個字節。
但是,當使用-Wall
, -pedantic
和-std=c++11
編譯時,我得到了臭名昭着的錯誤:
警告:可變長度數組是C99功能[-Wvla-extension]
我認為有道理: array::size()
是constexpr
,但它仍然是一個方法,在上面的函數中我們仍然需要取消引用一個指針,這不是constexpr
。
如果我嘗試類似的東西:
int test(std::array<char, 8>& data) {
char buffer[data.size() * 2];
[...]
}
gcc
(試用版5.2.0)似乎很高興:沒有警告。
但是對於clang++
(3.5.1),我仍然會收到一個抱怨可變長度數組的警告。
在我的情況下,我不能輕易改變test
的簽名,它必須采取指針。 那么......幾個問題:
在constexpr上下文中獲取std::array
指針大小的最佳/最標准方法是什么?
預期指針與引用的行為有何不同? 哪個編譯器對警告, gcc
或clang
是正確的?
我不知道2。
但對於1,我們可以這樣做:
template<class T, size_t N>
constexpr std::integral_constant<size_t, N> array_size( std::array<T, N> const& ) {
return {};
}
然后:
void test(std::array<char, 8>* data) {
using size=decltype(array_size(*data));
char buffer[size{}];
(void)buffer;
// [... some code ...]
}
或者:
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 ...]
}
最后,一個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 ...]
}
實例 。
好的舊C方式是定義,但C ++有const int
或C ++ 11 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;
}
它在沒有警告的情況下編譯,即使在Clang 3.4.1下使用-Wall -pedantic
對於第二個問題,我無法想象為什么gcc在這里指出和引用之間的區別。 它可以確定大小為常量的std::array
上的size()
方法是一個常量表達式 - 它應該允許兩者 - 或者它不能 - 並且它應該在兩者上發出相同的警告。 但它不僅涉及編譯器,還涉及標准庫實現。
真正的問題是pre-C ++ 11 std :: array不是標准庫的一部分, constexpr
也是僅從C ++ 11開始定義的。 所以在pre-C ++ 11模式下,兩個編譯器都將std :: array作為擴展進程,但是size
方法沒有辦法將其返回值聲明為常量expr。 這解釋了為什么Clang(以及面向指針的gcc)會發出警告。
但是如果你在c ++ 11模式下編譯原始代碼( -std=c++11
),你應該沒有警告,因為標准要求std::array
上的size()
方法是constexpr
。
(*)問題是關於最佳/最標准的 ; 我不能說什么是最好的方式,我也無法定義大多數標准 ,所以如果我想避免非C ++ 11編譯器上的可移植性問題,我會堅持使用。
如何在參數的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.