sizeof(array) in template
От:
Gregory
ICQ 300403361
Дата: 03.02.03 13:58
Оценка:
template <class T> class A
{
public :
A();
~A();
size_t Count() const ;
//.....
T value;
};
A<int [8]> IntArray;
A<int > IntValue;
Как прописать A::Count() так чтобы IntArray.Count() == 8, а IntValue.Count() == 1?
Не дай своим глазам увидеть, а ушам услышать то, что ты не сможешь объяснить.
Абрахам ван Хелсинг
Re: sizeof(array) in template
Здравствуйте, Gregory, Вы писали:
G>G>template <class T> class A
G>{
G>public :
G> A();
G> ~A();
G> size_t Count() const ;
G>//.....
G> T value;
G>};
G>A<int [8]> IntArray;
G>A<int > IntValue;
G>
G>Как прописать A::Count() так чтобы IntArray.Count() == 8, а IntValue.Count() == 1?
На нормальных компиляторах (GCC, Comeau), вот так:
template <class T>
class A
{
public :
size_t Count() const
{
return 1;
}
T value;
};
template <class D, int size>
class A<D[size]>
{
public :
size_t Count() const
{
return size;
}
T value;
};
Re: sizeof(array) in template
Здравствуйте, Gregory, Вы писали:
G>Как прописать A::Count() так чтобы IntArray.Count() == 8, а IntValue.Count() == 1?
Чтобы отличить массив от элемента, нужны дискриминирующие шаблоны.
Например, это сделано в
библиотеке Loki Андрея Александреску (есть порт на VC).
#include <Loki/TypeTraits.h>
template < class T >
class SizeAndCount
{
private :
template < bool to_be_array >
struct Count
{
enum { count = sizeof (T); } // случай дефолта
};
template <>
struct Count< true > // вот она, дискриминация по булевому признаку
{
enum { count = sizeof (T) / sizeof ( (*(T*)NULL)[0] ) };
};
// используем Loki'вскую штучку
typedef Count< TypeTraits<T>::isArray > TheCount;
public :
enum { size = sizeof (T); }
enum { count = TheCount::count };
};
Как это сделано:
// напишем обертку для различения типов
// (TypeManip.h)
template < class T >
class Type2Type
{
public :
Type2Type() {} // чтобы VC7 не ругался
};
// Свойства типа
// (TypeTraits.h)
template < class T >
class TypeTraits
{
// возьмем два типа заведомо разного размера...
typedef char yes_t;
typedef long no_t;
...
// и напишем функцию с 2 сигнатурами (прием "дискриминирующие ф-ции")
template < class T, size_t N >
yes_t _is_normal_array( Type2Type< T[N] > );
no_t _is_normal_array( ... );
// поскольку еще бывает "массив без границ", и этот тип отличен,
// добавим еще одну функцию
template < class T >
yes_t _is_unlim_array( Type2Type< T[] > );
no_t _is_unlim_array( ... );
// обратите внимание: нам не потребуются тела этих функций!
...
public :
...
// теперь все готово для определения
enum { isNormalArray = sizeof ( _is_normal_array(Type2Type<T>) ) == sizeof (yes_t),
isUnlimArray = sizeof ( _is_unlim_array(Type2Type<T>) ) == sizeof (yes_t),
isArray = isNormalArray || isUnlimArray
};
...
};
Перекуём баги на фичи!
Re: sizeof(array) in template
Я сразу извиняюсь за корявость. Ну, может что-то вроде такого?
#include <cstddef>
template <class T, int I>
struct Answer{
std::size_t Count()const
{
return I;
}
};
template <class T, int I>
Answer<T,I> fun(T (&ar)[I]){
return Answer<T,I>();
}
template <class T>
Answer<T,1> fun(T){
return Answer<T,1>();
}
int main(){
int a[10];
double b;
fun(a).Count();
fun(b).Count();
return 0;
}
Правда, если есть функция, то тогда проще из нее сразу же вернуть размер.
Of course, the code must be complete enough to compile and link .
Re[2]: sizeof(array) in template
От:
Gregory
ICQ 300403361
Дата: 03.02.03 15:08
Оценка:
Здравствуйте, comer, Вы писали:
C>На нормальных компиляторах (GCC, Comeau), вот так:
C>C>template <class T>
C>class A
C>{
C>public :
C> size_t Count() const
C> {
C> return 1;
C> }
C> T value;
C>};
C>template <class D, int size>
C>class A<D[size]>
C>{
C>public :
C> size_t Count() const
C> {
C> return size;
C> }
C> T value;
C>};
C>
Крайне не хотелось бы пораметризовать шаблон константой.
Не дай своим глазам увидеть, а ушам услышать то, что ты не сможешь объяснить.
Абрахам ван Хелсинг
Re[2]: sizeof(array) in template
От:
Кодт
Дата: 03.02.03 15:09
Оценка:
Здравствуйте, comer, Вы писали:
C>На нормальных компиляторах (GCC, Comeau), вот так:
А на ненормальных (старый GCC, VC6/VC7) — с помощью дискриминирующих функций.
Пример: порт библиотеки Loki.
Перекуём баги на фичи!
Re: sizeof(array) in template
Здравствуйте, Gregory, Вы писали:
G>Как прописать A::Count() так чтобы IntArray.Count() == 8, а IntValue.Count() == 1?
Если используешь компилятор, поддерживающий частичную специализацию шаблонов классов, то, например, так:
#include <iostream>
template <class T>
struct Counter
{
static const int count = 1;
};
template <class T, int i>
struct Counter<T[i]>
{
static const int count = i;
};
template <class T>
class A
{
public :
A() { }
~A() { }
int Count() const
{
return Counter<T>::count;
}
private :
T value;
};
A<int [8]> IntArray;
A<int > IntValue;
int main()
{
std::cout << "array: " << IntArray.Count() << std::endl;
std::cout << "value: " << IntValue.Count() << std::endl;
}
>como main.cpp
Comeau C/C++ 4.3.0.1 (Aug 21 2002 15:45:32) for MS_WINDOWS_x86
Copyright 1988-2002 Comeau Computing. All rights reserved.
MODE:strict warnings C++
>aout
array: 8
value: 1
Если компилятор поддерживает частичное упорядочение шаблонов функций, то, например, так:
#include <iostream>
template <class T>
int GetCount(T&)
{
return 1;
}
template <class T, int n>
int GetCount(T (&a)[n])
{
return n;
}
template <class T>
class A
{
public :
A() { }
~A() { }
int Count() const
{
return GetCount(value);
}
T value;
};
A<int [8]> IntArray;
A<int > IntValue;
int main()
{
std::cout << "array: " << IntArray.Count() << std::endl;
std::cout << "value: " << IntValue.Count() << std::endl;
}
>como main1.cpp
Comeau C/C++ 4.3.0.1 (Aug 21 2002 15:45:32) for MS_WINDOWS_x86
Copyright 1988-2002 Comeau Computing. All rights reserved.
MODE:strict warnings C++
>aout
array: 8
value: 1
В противном случае придется положиться на симуляцию частичной специализации:
#include <iostream>
typedef struct { char c[100]; } TrueType;
typedef char FalseType;
template <class T>
struct IsArray
{
private :
static T t_;
template <class T, int n>
static TrueType discriminator_(T (&a)[n]);
static FalseType discriminator_(...);
public :
enum { value = sizeof (discriminator_(t_)) == sizeof (TrueType) };
};
template <bool is_array /*true*/ >
struct Counter
{
template <class T, int n>
static int Get(T (&a)[n])
{
return n;
}
};
template <>
struct Counter<false /*is not array*/ >
{
template <class T>
static int Get(T&)
{
return 1;
}
};
template <class T>
class A
{
public :
A() { }
~A() { }
int Count() const
{
return Counter<IsArray<T>::value>::Get(value);
}
T value;
};
A<int [8]> IntArray;
A<int > IntValue;
int main()
{
std::cout << "array: " << IntArray.Count() << std::endl;
std::cout << "value: " << IntValue.Count() << std::endl;
}
>cl /GX main2.cpp
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 13.00.9466 for 80x86
Copyright (C) Microsoft Corporation 1984-2001. All rights reserved.
main2.cpp
Microsoft (R) Incremental Linker Version 7.00.9466
Copyright (C) Microsoft Corporation. All rights reserved.
/out:main2.exe
main2.obj
>main2
array: 8
value: 1
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re: sizeof(array) in template
От:
ssm
Дата: 03.02.03 15:28
Оценка:
Здравствуйте, Gregory, Вы писали:
Мой MSVC 6 не съел ни одно из приводимых решений
остаеться почитать А. Александеску, порадываться за тех у кого хороший компилятор, и начинать злые танцы с бубном:
#include <iostream>
template <typename T>
struct Sizer{
static T &createT();
typedef char SimpleType;
class ArrType{SimpleType dummy[2];};
static ArrType foo(void *);
static SimpleType foo(...);
template <typename T, bool isSimple>
struct SizerImpl{
static size_t result(){return 1;}
};
template <>
struct SizerImpl<T, false >{
static T &t;
static size_t result(){
return sizeof (T) / sizeof (t[0]);
}
};
public :
enum {isSimple = sizeof (SimpleType) == sizeof (foo(createT()))};
size_t Count(){
return SizerImpl<T, isSimple>::result();
}
};
int main(){
Sizer<int [10]> IntArray;
Sizer<int > IntValue;
std::cout << IntArray.Count() << std::endl;
std::cout << IntValue.Count() << std::endl;
return 0;
}
Re[2]: sizeof(array) in template
От:
Gregory
ICQ 300403361
Дата: 03.02.03 15:33
Оценка:
Здравствуйте, Кодт, Вы писали:
К>template< class T >
К>class SizeAndCount
К>{
К>private:
К> template< bool to_be_array >
К> struct Count
К> {
К> enum { count = sizeof(T); } // случай дефолта
К> };
К> template<>
К> struct Count< true > // вот она, дискриминация по булевому признаку
К> {
К> enum { count = sizeof(T) / sizeof( (*(T*)NULL)[0] ) };
К> };
К> // используем Loki'вскую штучку
К> typedef Count< TypeTraits<T>::isArray > TheCount;
К>public:
К> enum { size = sizeof(T); }
К> enum { count = TheCount::count };
К>};
К>[/c]
До "штучки" дело не дойдет, т.к. в случае любого встроеного типа получим:
enum { count = sizeof(T) / sizeof( (*(T*)NULL)[0] ) };
error C2109: subscript requires array or pointer type
Не дай своим глазам увидеть, а ушам услышать то, что ты не сможешь объяснить.
Абрахам ван Хелсинг
Re[2]: sizeof(array) in template
От:
Gregory
ICQ 300403361
Дата: 03.02.03 15:41
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:
Спасибо, Паша! Как всегда, твои ответы читать не только полезно, но и приятно!
Не дай своим глазам увидеть, а ушам услышать то, что ты не сможешь объяснить.
Абрахам ван Хелсинг
Re[3]: sizeof(array) in template
Здравствуйте, Gregory, Вы писали:
G>не только полезно, но и приятно!
Как говаривал мой учитель: "Как ангел по душе голыми пятками" — спасибо :-)
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[2]: sizeof(array) in template
От:
Gregory
ICQ 300403361
Дата: 03.02.03 16:11
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:
Эх, блин, сглазил.
template <class T, int n>
int GetCount(T (&a)[n])
{
return n;
}
Compiling...
Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8168 for 80x86
Copyright (C) Microsoft Corp 1984-1998. All rights reserved.
error C2265: '<Unknown>' : reference to a zero-sized array is illegal
Не дай своим глазам увидеть, а ушам услышать то, что ты не сможешь объяснить.
Абрахам ван Хелсинг
Re[3]: sizeof(array) in template
От:
ssm
Дата: 03.02.03 16:15
Оценка:
Здравствуйте, Gregory, Вы писали:
G>Эх, блин, сглазил.
здесьАвтор: ssm Дата: 03.02.03
Re: sizeof(array) in template
Здравствуйте, Gregory, Вы писали:
G> Эх, блин, сглазил.
G> Compiling...
G> Microsoft (R) 32-bit C/C++ Optimizing Compiler Version 12.00.8168 for
VC++ 6.0, действительно, бастует. Я проверял на VC++ 7.0.
Posted via RSDN NNTP Server 1.4.5 beta
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[3]: sizeof(array) in template
От:
Кодт
Дата: 03.02.03 16:26
Оценка:
Здравствуйте, Gregory, Вы писали:
G>Эх, блин, сглазил.
А как насчет еще одной сигнатуры?
template < class T >
int GetCount(T &a [])
{
assert(false ); // ибо нефиг.
return 0; // ну, или размер указателя -- считая, что на входе - не массив.
}
Перекуём баги на фичи!
Re[3]: sizeof(array) in template
Здравствуйте, Gregory, Вы писали:
G>Крайне не хотелось бы пораметризовать шаблон константой.
Почему?
Re[3]: sizeof(array) in template
От:
Кодт
Дата: 03.02.03 18:53
Оценка:
Здравствуйте, Gregory, Вы писали:
G>До "штучки" дело не дойдет, т.к. в случае любого встроеного типа получим:
G>enum { count = sizeof(T) / sizeof( (*(T*)NULL)[0] ) };
G>error C2109: subscript requires array or pointer type
Пардон.
Хорошо, тогда вынесем Count за пределы SizeAndCount:
template < bool to_be_array >
struct CountTool
{
template < class T >
struct Count
{
enum { size_of_item = sizeof (T) };
enum { perfect_count = 1 };
enum { count = sizeof (T) };
};
};
template <>
struct CountTool< true >
{
template < class T >
struct Count
{
enum { size_of_item = sizeof ((*(T*)NULL)[0]) };
enum { count = sizeof (T) / size_of_item };
};
};
template < class T >
struct SizeAndCount
{
enum { isArray = TypeTraits<T>::isArray };
enum { size = CountTool<false >::Count<T>::size_of_item };
enum { count = CountTool<isArray>::Count<T>::count };
};
Так даже изящнее получилось
Перекуём баги на фичи!
Re: sizeof(array) in template
От:
Gregory
ICQ 300403361
Дата: 04.02.03 08:33
Оценка:
Всем спасибо, господа!
Собрав воедино все, что вы написали по данной теме, удалось получить работующий код(т):
template <class TYPE>
struct CCount
{
private :
typedef long array_type;
typedef char intrinsic_type;
static TYPE val;
template <bool bIsArray = false > // = false просто для красоты
struct count
{
static size_t get()
{ return 1; }
};
typedef count<false > false_count; // а это для симетрии
typedef count<true > true_count;
friend true_count;
template <>
struct count<true >
{
static size_t get()
{ return sizeof (CCount::val)/sizeof (CCount::val[0]); }
};
static array_type discriminator(void *); // Паше Кузнецову посвящается
static intrinsic_type discriminator(...);
enum
{
IsArray = sizeof (array_type) == sizeof (discriminator(val))
};
public :
static size_t Get()
{ return count<IsArray>::get(); }
};
template <class TYPE>
struct MyStruct
{
TYPE val;
size_t Count() const
{ return CCount<TYPE>::Get(); }
};
Не дай своим глазам увидеть, а ушам услышать то, что ты не сможешь объяснить.
Абрахам ван Хелсинг
Re[2]: sizeof(array) in template
Извиняюсь за кучу байды, что я понаписал. Я хотел сказать явную специализацию
Of course, the code must be complete enough to compile and link .
Re[3]: sizeof(array) in template
От:
Gregory
ICQ 300403361
Дата: 04.02.03 09:08
Оценка:
Здравствуйте, Lorenzo_LAMAS, Вы писали:
LL>Извиняюсь за кучу байды, что я понаписал. Я хотел сказать явную специализацию
Прежде чем писать "байду", ты бы попробовал компильнуть. Фиг с ней со специализацией, главное — работает!
Не дай своим глазам увидеть, а ушам услышать то, что ты не сможешь объяснить.
Абрахам ван Хелсинг
Пока на собственное сообщение не было ответов, его можно удалить.
Удалить