I have a templatized function and I want to static_assert
that it's type has a size of three. This code illustrates what I'm trying to do, but doesn't work:
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 );
}
std::extent
is defined for built-in arrays. For std::array
use std::tuple_size
instead. I don't know some trait that works on both, but it's easy to write one:
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> > { };
and here's your foo
, corrected/generalized (live example):
template < typename T >
void foo( T&& param )
{
using U = typename std::remove_cv<typename std::remove_reference<T>::type>::type;
static_assert( 3 == array_size<U>::value, "param must have a size of 3" );
}
Prefer a universal reference T&& param
, otherwise only lvalues can be used.
This builds on iavr's solution.
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" );
}
I can't think of a way to write a single function that handles both, but this is what overloading is for.
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...
}
I suspect you're having this error because at compile time (which is when *static_assert* is evaluated) the dimensions of cArray and stdArray are unknown, and std::extent returns zero:
http://en.cppreference.com/w/cpp/types/extent
In fact, the error disappears if you change the condition to equal to zero:
static_assert( std::extent< T >::value == 0, "param is not zero" );
Nevertheless, as it has already been pointed out in other posts, std::extent won't work for std::array, only for built in arrays such as cArray
AFTER OP's EDIT: Now that you have modified foo to accept a reference, you'll have that std::extent reports 3 for cArray and 0 (zero) for stdArray. Hence, you'll carry on having the exception at compile time, because the dimension of stdArray is not 3.
来源:https://stackoverflow.com/questions/22712965/using-stdextent-on-stdarray