Using std::extent on std::array

后端 未结 4 1704
名媛妹妹
名媛妹妹 2021-01-13 08:21

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:<

相关标签:
4条回答
  • 2021-01-13 08:51

    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...
    }
    
    0 讨论(0)
  • 2021-01-13 08:55

    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" );
    }
    
    0 讨论(0)
  • 2021-01-13 08:56

    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.

    0 讨论(0)
  • 2021-01-13 09:15

    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.

    0 讨论(0)
提交回复
热议问题