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
От: comer США http://getboost.codeplex.com/
Дата: 03.02.03 14:50
Оценка:
Здравствуйте, 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;
};
getboost.codeplex.com
citylizard.codeplex.com
Re: sizeof(array) in template
От: Кодт Россия  
Дата: 03.02.03 15:07
Оценка: 14 (3)
Здравствуйте, 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
От: Lorenzo_LAMAS  
Дата: 03.02.03 15:07
Оценка:
Я сразу извиняюсь за корявость. Ну, может что-то вроде такого?
#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
От: Павел Кузнецов  
Дата: 03.02.03 15:10
Оценка: 28 (4)
Здравствуйте, 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
От: Павел Кузнецов  
Дата: 03.02.03 15:54
Оценка:
Здравствуйте, 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
От: Павел Кузнецов  
Дата: 03.02.03 16:24
Оценка:
Здравствуйте, 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
От: comer США http://getboost.codeplex.com/
Дата: 03.02.03 17:55
Оценка:
Здравствуйте, Gregory, Вы писали:

G>Крайне не хотелось бы пораметризовать шаблон константой.

Почему?
getboost.codeplex.com
citylizard.codeplex.com
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
От: Lorenzo_LAMAS  
Дата: 04.02.03 09:01
Оценка:
Извиняюсь за кучу байды, что я понаписал. Я хотел сказать явную специализацию
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>Извиняюсь за кучу байды, что я понаписал. Я хотел сказать явную специализацию

Прежде чем писать "байду", ты бы попробовал компильнуть. Фиг с ней со специализацией, главное — работает!
Не дай своим глазам увидеть, а ушам услышать то, что ты не сможешь объяснить.
Абрахам ван Хелсинг
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.