C++ 在std::数组上使用std::extent

C++ 在std::数组上使用std::extent,c++,arrays,templates,static-assert,C++,Arrays,Templates,Static Assert,我有一个模板化函数,我想static\u断言它的类型大小为3。此代码说明了我正在尝试执行的操作,但不起作用: template < typename T > void foo( T& param ) { // This line is the one that I need to figure out how to write static_assert( 3 == std::extent< T >::value, "param must have

我有一个模板化函数,我想
static\u断言它的类型大小为3。此代码说明了我正在尝试执行的操作,但不起作用:

template < typename T >
void foo( T& param )
{
    // This line is the one that I need to figure out how to write
    static_assert( 3 == std::extent< T >::value, "param must have a size of 3" );
}

int main( void )
{
    int cArray[3];
    std::array< int, 3 > stdArray;

    foo( cArray );
    foo( stdArray );
}
模板
无效foo(T¶m)
{
//这一行是我需要弄清楚如何写的
static_assert(3==std::extent::value,“param的大小必须为3”);
}
内部主(空)
{
int cArray[3];
std::数组标准数组;
富(凯瑞);;
foo(stdArray);
}

我怀疑您有此错误,因为在编译时(即计算*static_assert*时),cArray和stdArray的维度未知,并且std::extent返回零:

事实上,如果将条件更改为零,则错误将消失:

静态断言(std::extent::value==0,“参数不是零”);
然而,正如在其他文章中已经指出的,std::extent不适用于std::array,只适用于诸如cArray之类的内置数组

OP编辑后:
既然您已经修改了foo以接受引用,那么cArray的std::extent报告将为3,stdArray的报告将为0(零)。因此,您将在编译时继续出现异常,因为stdArray的维度不是3。

std::extent
是为内置数组定义的。对于
std::array
使用
std::tuple\u size
。我不知道什么特质对两者都有效,但很容易写出一个:

template<typename T>
struct array_size : std::extent<T> { };

template<typename T, size_t N>
struct array_size<std::array<T,N> > : std::tuple_size<std::array<T,N> > { };

更喜欢通用引用
T&¶m
,否则只能使用左值。

我想不出一种方法来编写一个同时处理这两个函数的函数,但重载就是为了这个

template <std::size_t N, typename T, std::size_t Bound>
void check_array_size( T (&)[Bound] )
{
    static_assert(Bound == N, "incorrect array size");
}

template <std::size_t N, typename T, std::size_t Bound>
void check_array_size( const std::array<T,Bound>& )
{
    static_assert(Bound == N, "incorrect array size");
}

template <std::size_t N>
void check_array_size( ... )
{
    static_assert(N<0, "argument is not an array");
}

template <typename T>
void foo(T& param)
{
    check_array_size<3>(param);
    // actual function implementation...
}
模板
无效检查数组大小(T(&)[绑定])
{
静态_断言(绑定==N,“数组大小不正确”);
}
模板
无效检查数组大小(常量std::数组&)
{
静态_断言(绑定==N,“数组大小不正确”);
}
模板
无效检查数组大小(…)
{
静态断言(N这是基于的解决方案

template < typename T >
void foo( T& param )
{
    static_assert( 3 == ( std::is_array< T >::value ? std::extent< T >::value : std::tuple_size< T >::value ), "param must have a size of 3" );
}
模板
无效foo(T¶m)
{
静态断言(3==(std::is_array::value?std::extent::value:std::tuple\u size::value),“参数的大小必须为3”);
}

尝试通过引用传递吗?我认为C数组不喜欢这样通过值传递。你应该解释它是如何“不工作”的。你有错误吗?哪些错误?我认为他/她得到的是“param的大小必须为3”在编译时。感谢Neil Kirk,我确实错过了那里的
&
。DrD是正确的,静态断言触发。这是正确的,但即使如此,他仍然会继续为cArray产生相同的错误,这是一个内置错误array@DrD这是为什么?它的大小在编译时就知道了,对吗?@aschepper你说得对,在T¶m更改之后就不知道了。问题是T正如OP定义的那样,foo接收数组的副本。在任何情况下,尽管std不接受T&becuase std::array,但错误仍然存在:extent@DrD好的,对于这种类型规范化,您需要使用
std::remove\u reference
后跟
std::remove\u cv
。将它们嵌入到类型特征中不是一个好主意ode>foo(T参数)
将收到指向数组的第一个元素的指针,而不是数组的副本。OP已被编辑。在纠正了我自己的错误后,它似乎起了作用!非常优雅的解决方案,恭喜!很好。另一种选择是使用数组_size=std::integral\u constant::value?std::extent:value:std::tupl定义
模板e_size::value>;
@iavr我在你的答案中也看到了使用关键字的
。你能给我解释一下这是怎么回事吗?@JonathanMee-see(从C++11开始)。前者(在我的答案中)只是
typedef
的一种替代语法。后者(如我之前的评论中)是
typedef
(大致)什么是普通类的类模板。如果你使用类型,这非常方便。@iavr哇,好的,所以我可以使用
static\u assert(3=array\u size,“param的大小必须为3”)
或者我甚至可以在
std::enable_if
中使用它吗?我相信我对类型别名的理解已经足够好了,但我仍然在试图弄清楚
std::integral_constant
和别名模板。无论如何,如果您想将其编辑到您的答案中,我很乐意接受。
template <std::size_t N, typename T, std::size_t Bound>
void check_array_size( T (&)[Bound] )
{
    static_assert(Bound == N, "incorrect array size");
}

template <std::size_t N, typename T, std::size_t Bound>
void check_array_size( const std::array<T,Bound>& )
{
    static_assert(Bound == N, "incorrect array size");
}

template <std::size_t N>
void check_array_size( ... )
{
    static_assert(N<0, "argument is not an array");
}

template <typename T>
void foo(T& param)
{
    check_array_size<3>(param);
    // actual function implementation...
}
template < typename T >
void foo( T& param )
{
    static_assert( 3 == ( std::is_array< T >::value ? std::extent< T >::value : std::tuple_size< T >::value ), "param must have a size of 3" );
}