#c #templates
Вопрос:
Как я могу создать класс с аргументом шаблона, который принимает массив любого размера? Я хочу передать массив в качестве аргумента шаблона, чтобы я мог хэшировать строку во время компиляции, что-то вроде этого:
template <typename>
struct CharArrayWrapper
{
};
template <typename T, int N>
struct CharArrayWrapper<T[N]>
{
static constexpr int stringLen() { N - 1; }
};
Комментарии:
1. В современном C вам ничего из этого не понадобится. Просто напишите хэш-функцию, как обычно, нажмите
constexpr
на нее, и она может сработать из коробки.
Ответ №1:
Мне это кажется довольно уродливым, но, похоже, это работает: https://godbolt.org/z/cd96Pjsdj
#include <algorithm>
#include <iostream>
template<typename T, std::size_t N>
struct MyArray
{
explicit MyArray(T (amp;data)[N]) : data_{data} {}
size_t size() const noexcept { return N; }
const T* get() const noexcept { return data_; }
private:
T (amp;data_)[N]{};
};
int main()
{
const char ac[]{"hey joe"}; // array of chars
MyArray tac{ac}; // templated array of chars
std::cout << "tac: " << tac.size() << ", " << tac.get() << "n";
const int ai[]{1, 2, 3}; // array of ints
MyArray tai{ai}; // templated array of ints
std::cout << "tai: " << tai.size() << ", ";
std::for_each(tai.get(), tai.get() tai.size(), [](auto i){ std::cout << i << " "; });
}
// Outputs:
// tac: 8, hey joe
// tai: 3, 1 2 3
Если вам действительно нужна версия, которая делает копию вашего массива в шаблонную структуру: https://godbolt.org/z/rs5zs6Ysr
#include <algorithm>
#include <iostream>
template<typename T, std::size_t N>
struct MyArray
{
explicit MyArray(const T (amp;data)[N]) { std::copy(data, data N, data_); }
size_t size() const noexcept { return N; }
const T* get() const noexcept { return data_; }
private:
T data_[N]{};
};
int main()
{
char ac[]{"hey joe"}; // array of chars
MyArray tac{ac}; // templated array of chars
ac[0] = 'H';
std::cout << "ac: " << sizeof(ac)/sizeof(char) << ", " << ac << "n";
std::cout << "tac: " << tac.size() << ", " << tac.get() << "n";
int ai[]{1, 2, 3}; // array of ints
MyArray tai{ai}; // templated array of ints
ai[0] = 10;
std::cout << "ai: " << tai.size() << ", ";
std::for_each(ai, ai sizeof(ai)/sizeof(int), [](auto i){ std::cout << i << " "; });
std::cout << "n";
std::cout << "tai: " << tai.size() << ", ";
std::for_each(tai.get(), tai.get() tai.size(), [](auto i){ std::cout << i << " "; });
std::cout << "n";
}
// Outputs:
// ac: 8, Hey joe
// tac: 8, hey joe
// ai: 3, 10 2 3
// tai: 3, 1 2 3
Примечание Я добавил const
к типу data
параметра. В противном случае при передаче массивов const конструктору выводимый тип T
будет const
препятствовать изменению элемента data_
.
Идея этого решения взята из эффективной современной книги Скотта Мейера по C , Пункт 1 (Вывод типов) и раздел, посвященный аргументам массива; там вы можете увидеть следующий фрагмент кода:
// return size of an array as a compile-time
template<typename T, std::size_t N>
constexpr std::size_t arraySize(T (amp;)[N]) noexcept {
return N;
}
Объяснение, также из книги, было бы:
- Функции могут объявлять параметры, которые являются ссылками на массивы.
- В этом случае тип, для которого выводится
T
, является фактическим типом массива. - Этот тип включает размер массива, поэтому в моем примере
T
выводится значениеconst char [8]
(для массива символовac
), а тип параметраdata
(ссылка на этот массив) равенconst char (amp;)[8]
.