簡體   English   中英

constexpr上下文中std :: array指針的size()

[英]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的簽名,它必須采取指針。 那么......幾個問題:

  1. 在constexpr上下文中獲取std::array 指針大小的最佳/最標准方法是什么?

  2. 預期指針與引用的行為有何不同? 哪個編譯器對警告, gccclang是正確的?

我不知道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 因此,如果您希望編譯器知道數組的大小是編譯時常量,那么最便攜(*)的方法是使它成為constconstexpr

#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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM