Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >constexpr上下文中std::数组指针的大小()

constexpr上下文中std::数组指针的大小()
EN

Stack Overflow用户
提问于 2015-10-06 05:42:24
回答 3查看 899关注 0票数 11

假设我有这样的功能:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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-扩展

我认为这是有意义的:array::size()constexpr,但它仍然是一种方法,在上面的函数中,我们仍然必须取消引用指针,而不是constexpr

如果我尝试这样的方法:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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. 指针与引用的行为是否存在差异?关于警告,哪个编译器是对的,gcc还是clang
EN

回答 3

Stack Overflow用户

发布于 2015-10-06 07:03:09

我不知道大约2。

但对于1,我们可以这样做:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
template<class T, size_t N>
constexpr std::integral_constant<size_t, N> array_size( std::array<T, N> const& ) {
  return {};
}

然后:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void test(std::array<char, 8>* data) {
  using size=decltype(array_size(*data));
  char buffer[size{}];
  (void)buffer;
  // [... some code ...]
}

另一种选择是:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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清理:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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 ...]
}

实例化

票数 2
EN

Stack Overflow用户

发布于 2015-10-06 07:12:32

好的老C方式应该是一个定义,但是C++有const int或C++11 constexpr。因此,如果您希望编译器知道数组的大小是一个编译时间常数,最可移植的(*)方法是使其成为constconstexpr

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#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;
}

它在没有警告的情况下编译,即使在Clang3.4.1下使用-Wall -pedantic

关于第二个问题,我想不出gcc为什么在这里把指针和裁判区分开来。要么它可以确定大小为常数的std::array上的std::array方法是一个常量表达式--而且它应该允许两者都允许--要么它不能--而且它应该对两者发出相同的警告。但它不仅关系到编译器,而且关系到标准库的实现。

真正的问题是,pre++11 std::array不是标准库的一部分,constexpr也是从C++11开始定义的。因此,在预C++11模式下,两个编译器都将std::array作为扩展处理,但是size方法无法将其返回值声明为常量扩展。这就解释了为什么Clang (和gcc面对一个指针)发出警告。

但是,如果您以c++11模式(-std=c++11)编译原始代码,您应该没有警告,因为标准要求std::array上的size()方法是constexpr

(*)问题是关于最佳/最标准的;我不能说什么是最好的方法,我也不能定义大多数标准,所以如果我想避免非C++11编译器的可移植性问题,我就坚持使用什么。

票数 0
EN

Stack Overflow用户

发布于 2015-10-06 23:01:33

如何在参数的解密类型上使用std::tuple_size

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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 ...]
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/32971566

复制
相关文章

相似问题

添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文