如何将std::array<char, N> 转换为 char (&dest)[N]?

7

如何将std::array<char, N>传递给这样的函数:


template<size_t N>
void safe_func(char (&dest)[N]);

我尝试这个:

#include <array>

template <size_t N> using SafeArray = char[N];

template <size_t N> void safe_func(char (&dest)[N]) {}

int main() {
  SafeArray<10> a1;
  safe_func(a1);
  std::array<char, 10> a2;
  safe_func(*static_cast<SafeArray<10> *>(static_cast<void *>(a2.data())));
}

它能够工作,但我怀疑可能是我的类型转换有问题,而且在其他编译器或平台(我使用gcc / linux / amd64)上,我遇到了错误的引用?


我认为这不会出问题,但你可能需要阅读一下这个链接:https://dev59.com/mlgR5IYBdhLWcg3wV78y - NathanOliver
你可以简单地使用reinterpret_cast转换引用:这样会更短,也更少出错。但是再次强调,这种编程方式是危险的。如果元素类型和大小不匹配,你可能不会注意到,但是损害已经造成了。 - Red.Wave
1个回答

8

一种方式:

template<class T, size_t N>
using c_array = T[N];

template<class T, size_t N>
c_array<T, N>& as_c_array(std::array<T, N>& a) {
    return reinterpret_cast<T(&)[N]>(*a.data());
}

int main() {
    std::array<int, 2> a;
    int(&b)[2] = as_c_array(a);
}

标准要求std::array是一个聚合体,它的唯一成员是T[N]std::array::data()返回指向该成员的指针。由于聚合体的地址与其第一个成员的地址重合,调用和解引用std::array::data()并不是严格必要的,reinterpret_cast<T(&)[N]>(a)同样有效。

std::array起源于boost,它的唯一目的是为内置数组T[N]提供标准容器接口(begin/end/size/empty/etc.),并且没有额外开销,零成本抽象。因此,你基本上可以将boost::array<T, N>T[N]相互转换,尽管这可能会违反别名规则(编译器假定boost::array<T, N>T[N]指向不同的对象,因此你需要知道如何在特定情况下处理)。

标准文档没有解释原理,只用非常弱和模糊的术语表达了std::array的要求。因此,人们会想知道它是否真的只有T[N]成员,而没有其他所谓的外星类型来满足要求。


2
小问题:标准在哪里说 std::array 包含 T[N] - geza
1
@geza 标准规定它是一个聚合体,用于存储多个元素的连续存储。除了 T[N] 之外,没有任何东西符合这个描述。 - Maxim Egorushkin
1
当然,但我没有在标准中找到std::array包含T[N]的内容。它可以是任何东西,不仅仅是通常可访问的类型(例如,NULL未定义,它确切的含义是什么)。但这只是吹毛求疵,因为std::array肯定是实现为T[N],否则就没有意义了。 - geza
1
我喜欢这个答案如何一举概括了C++的历史和MO,同时以实用和合法的方式回答了问题。满分:D - Lightness Races in Orbit
1
@MaximEgorushkin:我总是觉得很有趣,T[0] 不是良构的,而 new T[0] 是良构的,但话说回来,我很容易被逗乐。 - Lightness Races in Orbit
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接