Всё началось с того, что при программировании я использовал несколько вспомагательных шаблонных функций, вроде memzero(), которая является обёрткой над memset() и принимает один параметр вместо трёх:
template < typename T >Также я завёл один вспомогательный макрос для очистки статических С-arrays:
inline void *memzero(T *p)
{
return memset(p, 0, sizeof(T));
}
#define zeroarray(a) memset(a, 0, sizeof(a));Мне хотелось оформить этот макрос тоже в виде функции, но вся загвоздка в том, что определив параметр как указатель на тип, применить к нему sizeof() нельзя. Первая попытка оформить функцию в виде шаблона выглядила так:
template < typename T, size_t N >Но в данном случае компилятор С++ не может вывести размер массива, и sizeof() выдаёт типичные 4 байта для 32-битной конфигурации. Тепение моё лопнуло и я полез в гугл: после 5 минут гугления выяснилось, что существует такое решение этой проблемы:
inline void zeroarray(T a[N])
{
return memset(a, 0, sizeof(a));
}
template < typename T, size_t N >Я не эксперт в С++, и мне сложно понять, что это за китайская грамота написана в виде параметра функции. Понимаю только одно - выглядит фигово :)
inline void zeroarray(T(&a)[N])
{
return memset(a, 0, sizeof(T) * N);
}
Запись вида inline void zeroarray(T a[N]) для компилятора тоже самое что и inline void zeroarray(T* a). Т.е. он не понимает разницы из-за наследния С. Где имя массива есть указатель на первый его элемент. Из-за этого систем типов С++ не может вывести что здесь происходит.
ОтветитьУдалитьЗапись же ввиде inline void zeroarray(T(&a)[N])
Говорит компилятору что эта функция принимает ссылку на какой-то тип, он пытается вывести и ты получаешь что твой тип есть T[N].
Т.е. принципиальный момент во всем этом именно в разнице указатель на массив и ссылка на массив. И опять так из-за обратной совместимости с С.
P.S. Более детально можешь почитать в книге "Шаблоны С++" Джоссатиса и Вандервуда.
Вообще в этом месте С++ кривоват. Правда утверждать что T[N] - тип, немного странно. Но спасибо за разъяснение.
ОтветитьУдалитьПривет!
ОтветитьУдалитьНу не сказал что это проблема С++ как такового, т.к. современный С++ (точнее если использовать его именно как С++ а не как расширение С) выглядит давольно стройно, если не пытаться залазить в его темные места, которые находятся прямо на границе стандарта.
Насчет "утверждать что T[N] - тип, немного странно" оно кажется странным только до тех пор пока это выражение не переписать ввиде:
typedef int TypeOfIntArrayOf10Elemets[10];
После этой записи TypeOfIntArrayOf10Elemets с точки зрения типов С++ есть полноценный тип и его можно ипользовать также как или любой другой.
Заголовок твоей функции в таком случае мог бы выглядеть следующим образом (к сожаление это не валидный код для текущего С++, это скорее псевдокод для понятности что происходит)
typedef T ArrayOfNElements[N];
inline void zeroarray(ArrayOfNElements& a)
Хотя согласен, что выглядит это немножко странно, но если привыкнуть и вникнуться в это, потом можно получать истинное удовольствие от изящных решений.
Про typedef int TypeOfIntArrayOf10Elemets[10] я действительно не знал. Спасибо за хинт.
ОтветитьУдалить