Размер встроенного многомерного массива с использованием функции шаблона variadic - PullRequest
3 голосов
/ 28 ноября 2011

В C ++ 11 можно создать функцию, которая возвращает размер (количество элементов) встроенного одномерного массива во время компиляции, используя constexpr. Пример ниже:

template <typename T, std::size_t N>
constexpr std::size_t size(T (&array)[N])
{
     return N;
}

Это превосходная альтернатива ARRAY_SIZE и аналогичным макросам imo.

Однако это вернет только размер самого значительного измерения встроенного многомерного массива.

Я использую следующую функцию для определения размера встроенного двумерного массива:

template <typename T, std::size_t N, std::size_t N2>
constexpr std::size_t size(T (&array)[N][N2])
{
     return N * N2;
}

В идеале было бы очень полезно иметь функцию, которая возвращает размер встроенного массива с произвольным числом измерений. Я думал, что шаблоны variadic могут помочь, но я не мог увидеть способ распаковки параметров шаблона, поскольку передается только один аргумент. Возможна ли такая функция?

Заранее спасибо.

Ответы [ 3 ]

5 голосов
/ 28 ноября 2011
#include <type_traits>
#include <cstdlib>

template <typename T>
constexpr size_t size(const T&) noexcept
{
    return sizeof(T)/sizeof(typename std::remove_all_extents<T>::type);
}

Пример:

#include <cstdio>
int main()
{
    int a[3][4][7][12];
    char f[6];

    printf("%lu == %ld ?\n", size(a), 3*4*7*12);
    printf("%lu == %ld ?\n", size(f), 6);

    return 0;
}
3 голосов
/ 28 ноября 2011
template<typename T> constexpr int size(T const&) { 
  return 1; 
}

template<typename T, int N> constexpr int size(T const (&a)[N]) { 
  return N * size(a[0]); 
} 
2 голосов
/ 28 ноября 2011

Вы ищете std::extent. C ++ 11 §20.9.5:

template <class T, unsigned I = 0> struct extent;

Если T не является типом массива, или если он имеет ранг, меньший или равный I, или если I равен 0, а T имеет тип «массив неизвестной границы U», то 0; в противном случае граница (8.3.4) I-го измерения T, где индексирование I начинается с нуля.

Использование, также из стандарта, префикс extent с std:: при необходимости:

assert((extent<int[2][4], 1>::value) == 4);

Возможно, вам также следует использовать это для замены вашей пользовательской функции size.

Редактировать: К сожалению, теперь я прочитал в конце вопроса: vP. Вам также нужно std::remove_extent.

template< typename multi_array, bool = std::is_array< multi_array >::value >
struct total_extent;

template< typename multi_array >
struct total_extent< multi_array, false > {
    enum { value = 1 };
};

template< typename multi_array >
struct total_extent< multi_array, true > {
    enum {
        value = std::extent< multi_array >::value
              * total_extent< typename std::remove_extent< multi_array >
                              ::type >::value
    };
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...