获取数组指针模板参数的大小

Get size of an array-pointer template parameter

本文关键字:参数 数组 指针 获取      更新时间:2023-10-16

我想知道是否可以自动推断数组的大小,该数组作为模板参数传递,而不(显式(传递其大小。

以下代码在g++4.8和clang++3.3(使用-std=c++11 -Wall(上都编译了warning-less。

#include <iostream>
template<const int* arr>
struct array_container
{
    static constexpr int val = arr[1];
    array_container() {
        std::cout << val << std::endl;
    }
//  static constexpr int arr_size = ??;
};
constexpr int one[] = { 1 };
constexpr int two[] = { 1, 2 };
int main()
{
//  array_container<one> array_one;
    array_container<two> array_two;
//  (void) array_one;
    (void) array_two;
    return 0;
}

但是,如果我删除main()中的两个注释符号,那么两个编译器都会出现越界错误。

现在,这很酷。尽管const int* arr的类型是指针,但编译器不知何故知道数组的大小。有没有办法得到arr的大小,例如在array_container中完成我的评论?

当然,你不允许进入

  • 使用任何宏
  • 将大小存储在arr中(例如,传递std::数组作为模板参数:constexpr std::array<int, 1> one = { 1 },或在字符串中使用类似''的结束标记(
  • 对于不能自动推导(array_container<1, one> array_one(的大小,请使用额外的模板参数

也许C++11标准库<type_traits>头中的std::extent模板就是您想要的:

#include <iostream>
#include <type_traits>
constexpr int one[] = { 1 };
constexpr int two[] = { 1, 2 };
int main()
{
    std::cout << std::extent<decltype(one)>::value << std::endl;
    std::cout << std::extent<decltype(two)>::value << std::endl;
    return 0;
}

输出:

1
2
template<size_t size>
constexpr size_t arraySize ( const int ( &arrayRef ) [size] ) {
    return size;
}
int main(){
    int A[1];
    int B[2];
    cout << arraySize(A) << arraySize(B);
    return 0;
}

我相信像这样的东西就是你想要的,使用数组引用。声明数组引用的语法看起来有点像函数指针的语法。此函数模板接受一个名为arrayRef的数组引用,它可以防止数组到指针的衰减,从而保留有关数组大小的编译时信息。正如您所看到的,模板参数对于编译器是隐式的。请注意,只有在编译时可以推导出大小时,这才能起作用。有趣的是,在不命名arrayRef的情况下,这应该仍然有效。为了使上述模板更加有用,您还可以添加一个模板参数来推断数组的类型。为了清楚起见,我省略了它。

可能不会,因为SFINAE只发生在即时上下文中,而该错误来自于constexpr中的UB导致编译时错误的要求,我认为这不是即时的。你可以尝试一个在UB上停止的递归SFINAE,但即使它有效,你也必须检查标准,并希望它不会改变(因为它相当模糊和新(。

简单的方法是ise函数来推导数组大小,必须显式地将其传递给类型,然后将其存储在auto中。可能不是你想要的。

有人建议允许从值参数中推导类型参数,因此您可以等待这些参数。

不是一个可靠的答案,更多的是一个扩展的评论,所以标记为社区维基。

这确实是可能的。我用SFINAE找到了一个解决方案。如果索引超出范围(本例中的第3行(,它基本上会产生替换错误:

template<class C>
static yes& sfinae(typename val_to_type<
    decltype(*C::cont::data), *(C::cont::data + C::pos)>::type );
template<class C>
static no& sfinae(C );

完整的源代码在github上。

只有两个缺点:

  1. 您必须指定数组的类型(这是不可避免的(
  2. 它只适用于g++4.8.1和clang 3.3。g++对于空字符串失败(带有编译器错误(。如果有人能为其他编译器进行测试,我们将不胜感激