Re[11]: sizeof(array) in template
От: Denn  
Дата: 19.02.03 10:52
Оценка:
Круто, Андрей!!!
Предлагаю сделать читабельней

typedef char    YES;
struct NO {char size[2];};

template<typename T_> struct is_array_
{
  template <typename U_> static NO is(U_* const*);
  static YES is(...);
  static T_* ret();
  enum { value = sizeof( is(ret()) ) == sizeof(YES)  };
};

template<typename T> struct is_array
{
  static YES is(const void*);
  static NO is(...);
  static T& ret(); 
  enum { value = sizeof( is(ret()) ) == sizeof(YES) && is_array_<T>::value };
};

template<> struct is_array<void>
{
  enum { value = 0 };
};
Re[12]: sizeof(array) in template
От: Кодт Россия  
Дата: 19.02.03 11:20
Оценка: 3 (1)
Здравствуйте, Denn, Вы писали:

D>Круто, Андрей!!!

D> Предлагаю сделать читабельней

И еще читабельнее

template < typename T > struct test_array
{
private:
  typedef char NO;
  typedef struct { NO _[2]; } YES;
  enum { yes = sizeof(YES) };
  
  template < class U > static NO is1(U* const*);
  static YES is1(...);
  static T* ret1();
  
  static YES is2(const void*);
  static NO is2(...);
  static T& ret2();

public:
  enum { is_not_pointer  = sizeof(is1(ret1())) == yes };
  enum { is_pointer_like = sizeof(is2(ret2())) == yes };
  
  enum { is_array = is_not_pointer && is_pointer_like };
};
Перекуём баги на фичи!
Re[13]: sizeof(array) in template
От: Denn  
Дата: 19.02.03 12:30
Оценка:
К>И еще читабельнее

Только вот этот код
К>
К>  static T& ret2();
К>


требует специализации для типа void шаблона test_array
template<> struct test_array<void>
{
  enum { value = 0 };
};
Re[11]: sizeof(array) in template
От: Denn  
Дата: 19.02.03 12:51
Оценка:
Да!!! Чуть не забыл!

Андрей и Кодт, следует отметить, что код:

static T_& ret();


Создает более серьезные проблемы, попробуйте:
is_array<int[]>::value


Мой вариант, распознает корректо. Рекомендую вам также использовать идиому упрятывания оригинального типа в объект.
Есть несколько вариантов, вот, к примеру, еще один:

template <class T>
 struct Type2Type {
        typedef T OriginalType;
        Type2Type() {};
 };
Re[12]: sizeof(array) in template
От: Andrew S Россия http://alchemy-lab.com
Дата: 19.02.03 13:40
Оценка:
D>
D>    int i[3];
D>    cout << typeid(fun(i)).name() << sizeof(fun(i)) << endl;   
D>    cout << typeid(i).name() << sizeof(i) << endl;
D>


D> Возвращается указатель!!! Однако T выводится как массив!

D> Предлагаю использовать это

Т.е. если размер типа не равен оному после пропуска через такую функцию — это якобы массив.
А если sizeof(T[]) == sizeof(T*) ?
Например, char * и char[4].
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[13]: sizeof(array) in template
От: Denn  
Дата: 19.02.03 13:59
Оценка: 5 (1)
Здравствуйте, Andrew S, Вы писали:

AS>Т.е. если размер типа не равен оному после пропуска через такую функцию — это якобы массив.

AS>А если sizeof(T[]) == sizeof(T*) ?
AS>Например, char * и char[4].

В общем, теперь, я признаюсь, мне разонравилась идея сравнивания посредством размеров. Слишком, геморрой развивает. Особенно, если типы-параметры можно просто сравнить. Например, так:

template<class T1, class T2>
class TypeIdentity {

    template<class TT>
        struct compilerCompare_ {
        enum {flag = 0};
        };

    template<>
        struct compilerCompare_<T2> {
        enum {flag = 1};
        };

public:
    enum { equal = (TypeIdentity<T1, T2>::compilerCompare_<T1>::flag == 1) };

};


Надо работать на том, что в случае массива возникает различие!!!
Re[12]: sizeof(array) in template
От: Андрей Тарасевич Беларусь  
Дата: 19.02.03 18:01
Оценка:
Здравствуйте, Denn, Вы писали:

D> Про задачу определения массив или не массив. Код я опубликую в следующем посте, но настоятельно рекомендую порешать эту задачу самому. Вы можете получить просто не детское удовольствие решив ее!!!


D> Смотрите, пусть у нас есть шаблонная функция. Например:


D>

D>
D>template<class T>
D>T fun(T &t);
D>


D> Что произойдет при "передаче" массива?


D>


D>
D>    int i[3];
D>    cout << typeid(fun(i)).name() << sizeof(fun(i)) << endl;   
D>    cout << typeid(i).name() << sizeof(i) << endl;
D>


D> Возвращается указатель!!! Однако T выводится как массив!

D> Предлагаю использовать это

Любое решение, основанное на этом принципе, будет обладать огромным недостатком, фактически делающим это решение неприемлемым. Это поведение является эксклюзивным для MSVC++ и не имеет места в стандартном компиляторе. Другими словами, это поведение является багом/расширением MSVC++. При использовании стандартного компилятора подобный код вызовет ошибку компиляции с сообщением о том, что функция не может возвращать результат типа "массив". Мое решение таким недостатком не обладает и использует только стандартное подмножество свойств компилятора MSVC++.
Best regards,
Андрей Тарасевич
Re[13]: Just a code...
От: Андрей Тарасевич Беларусь  
Дата: 19.02.03 18:05
Оценка:
Здравствуйте, Denn, Вы писали:

D>
D>        typedef char YES;
D>        typedef long NO;
D>        
D>        template <class U>
D>        class ArrayTester
D>        {
D>        template <class T> struct Original {};
D>            template<class T> 
D>                static T(* ReturnTModificator( Original<T> ) )(Original<T>);

D>            template<class T> 
D>                static NO Comparator(  T(*)(Original<T>)  );
D>                static YES Comparator(...);
D>            public:
D>                enum {
D>                    value = sizeof(Comparator(ReturnTModificator( Original<U>() )))
D>                            == sizeof(YES)
D>                };
D>        };

D>


Код будет вызывать ошибку компиляции при использовании любого стандартного компилятора. Это фактически сводит практическую ценность такого решения к нулю.
Best regards,
Андрей Тарасевич
Re[12]: sizeof(array) in template
От: Андрей Тарасевич Беларусь  
Дата: 19.02.03 18:15
Оценка:
Здравствуйте, Denn, Вы писали:

D>
D>static T_& ret(); 
D>


D> Создает более серьезные проблемы, попробуйте:

D>
D>is_array<int[]>::value
D>


Этот код не "создает более серьезные проблемы". Этот код просто создает проблемы, ибо никаких других проблем пока обнаружено не было. Эта проблема (опять же глюк MSVC++, ибо внутренне он считает, что 'int[]' — это массив нулевого размера) легко исправляется так:

template<typename T_> struct is_array
{
  static char (&is(const void*))[2];
  static char (&is(...))[1];
  static T_* ret(); 
  enum { value = (sizeof(is(*ret())) - 1) && is_array_<T_>::value };
};
Best regards,
Андрей Тарасевич
Re[11]: sizeof(array) in template
От: Кодт Россия  
Дата: 19.02.03 18:22
Оценка:
Здравствуйте, Андрей Тарасевич, Вы писали:

<>

В общем, поздравляю с заслуженным взятием рейхстага.

Надо послать ноту Андрею Александреску — с него, имхо, !!!
Перекуём баги на фичи!
Re[14]: sizeof(array) in template
От: Андрей Тарасевич Беларусь  
Дата: 19.02.03 18:57
Оценка:
Здравствуйте, Denn, Вы писали:

D>Здравствуйте, Andrew S, Вы писали:


AS>>Т.е. если размер типа не равен оному после пропуска через такую функцию — это якобы массив.

AS>>А если sizeof(T[]) == sizeof(T*) ?
AS>>Например, char * и char[4].

D> В общем, теперь, я признаюсь, мне разонравилась идея сравнивания посредством размеров. Слишком, геморрой развивает.


Никакого геммороя она не развивает. Не надо просто пользоваться какими-то странными случайно придуманными типами. Техника давно уже отработана — использовать для обозначения разных результатов ссылки на массивы из 'char' разного размера. Различие размеров в этом случае гарантировано. Более того, конкретные значения размеров в этом случае гарантированы.

D>Особенно, если типы-параметры можно просто сравнить. Например, так:


D>
D>template<class T1, class T2>
D>class TypeIdentity {

D>    template<class TT>
D>        struct compilerCompare_ {
D>        enum {flag = 0};
D>        };

D>    template<>
D>        struct compilerCompare_<T2> {
D>        enum {flag = 1};
D>        };

D>public:
D>    enum { equal = (TypeIdentity<T1, T2>::compilerCompare_<T1>::flag == 1) };

D>};
D>


Опять завязка на эксклюзивную багофичу MSVC++. В стандартном С++ запрещатеся выполнять явную специализацию вложенного класса без специализации внешнего.

D> Надо работать на том, что в случае массива возникает различие!!!


Тоже, как уже говорилось, эксклюзивная багофича MSVC++.

Пойми, что задача состоит не в поиске нестандартных эксклюзивных решений для MSVC++, а в поиске стандартных С++ решений, которые работают и на MSVC++ в том числе.
Best regards,
Андрей Тарасевич
Re[11]: sizeof(array) in template
От: Владик Россия  
Дата: 20.02.03 07:50
Оценка:
Здравствуйте, Андрей Тарасевич, Вы писали:

АТ>
АТ>template<typename T_> struct is_array_
АТ>{
АТ>  template <typename U_> static char (&is(U_* const*))[1];
АТ>  static char (&is(...))[2];
АТ>  static T_* ret();
АТ>  enum { value = sizeof(is(ret())) - 1 };
АТ>};
АТ>


Я, конечно, извиняюсь, но не мог бы кто-нибудь построчно разжевать мне этот кусочек кода?
Как все запущенно...
Re[12]: sizeof(array) in template
От: Владик Россия  
Дата: 20.02.03 08:03
Оценка:
АТ>>
АТ>>  template <typename U_> static char (&is(U_* const*))[1];
АТ>>

В>Я, конечно, извиняюсь, но не мог бы кто-нибудь построчно разжевать мне этот кусочек кода?

Кажется все-таки понял Остался один вопросик — нафига в оставленной выше строке const?
Как все запущенно...
Re[11]: sizeof(array) in template
От: MaximE Великобритания  
Дата: 20.02.03 08:08
Оценка:
Здравствуйте, Андрей Тарасевич, Вы писали:

АТ>А если для отличения массива от указателя в compile-time VC6 сделать так:


АТ>
АТ>template<typename T_> struct is_array_
АТ>{
АТ>  template <typename U_> static char (&is(U_* const*))[1];
АТ>  static char (&is(...))[2];
АТ>  static T_* ret();
АТ>  enum { value = sizeof(is(ret())) - 1 };
АТ>};
АТ>


АТ>Умея делать это, я думаю, отличить массив от любого другого типа особого труда не составит:


АТ>
АТ>template<typename T_> struct is_array
АТ>{
АТ>  static char (&is(const void*))[2];
АТ>  static char (&is(...))[1];
АТ>  static T_& ret(); 
АТ>  enum { value = (sizeof(is(ret())) - 1) && is_array_<T_>::value };
АТ>};

АТ>template<> struct is_array<void>
АТ>{
АТ>  enum { value = 0 };
АТ>};
АТ>


Понятно, что Метод основан на стандартном неявном преобразовании массива к указателю.
А как быть с этим:
template<class P>
struct Crafty
{
    operator P*() { return 0; }
};

template<>
struct Crafty<bool>
{
};

typedef Crafty<bool> Crafty1;
typedef Crafty<void> Crafty2;
typedef Crafty<int> Crafty3;

typedef Crafty1 CRAFTIES[2];

int _tmain(int argc, _TCHAR* argv[])
{
    cout << is_array<Crafty1>::value << endl;
    cout << is_array<Crafty2>::value << endl;
    cout << is_array<Crafty3>::value << endl;
    cout << is_array<CRAFTIES>::value << endl;
    return 0xDead;
}
Re[12]: sizeof(array) in template
От: Павел Кузнецов  
Дата: 20.02.03 10:09
Оценка: 78 (5)
Здравствуйте, MaximE, Вы писали:


ME>Понятно, что Метод основан на стандартном неявном преобразовании массива к указателю.

ME>А как быть с этим: <... использование типов, с определенным пользователем приведением к указателю ...>

А для этого можно воспользоваться тем фактом, что определенные пользователем приведения типов используются только один раз, а встроенные — многократно. Т.е. достаточно заставить компилятор выполнять на одно преобразование больше, чем нужно, и будут работать только встроенные преобразования:

struct PointerShim
{
  PointerShim(const volatile void*);
};

template<typename T_> struct is_array_
{
  template <typename U_>
  static char (&is(U_* const*))[1];

  static char (&is(...))[2];
  static T_* ret();

  enum { value = sizeof(is(ret())) - 1 };
};

template<typename T_> struct is_array
{
  static char (&is(PointerShim))[2];
  static char (&is(...))[1];
  static T_& ret(); 

  enum { value = (sizeof(is(ret())) - 1) && is_array_<T_>::value };
};

template<> struct is_array<void>
{
  enum { value = 0 };
};


template<class P>
struct Crafty
{
    operator P*() { return 0; }
};

template<>
struct Crafty<bool>
{
};

typedef Crafty<bool> Crafty1;
typedef Crafty<void> Crafty2;
typedef Crafty<int>  Crafty3;

typedef Crafty1 CRAFTIES[2];

int main()
{
  using namespace std;
  cout << is_array<Crafty1>::value << endl;
  cout << is_array<Crafty2>::value << endl;
  cout << is_array<Crafty3>::value << endl;
  cout << is_array<CRAFTIES>::value << endl;
  return 0;
}


0
0
0
1
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[13]: sizeof(array) in template
От: MaximE Великобритания  
Дата: 20.02.03 10:16
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>Здравствуйте, MaximE, Вы писали:


ПК>

ME>>Понятно, что Метод основан на стандартном неявном преобразовании массива к указателю.
ME>>А как быть с этим: <... использование типов, с определенным пользователем приведением к указателю ...>

ПК>А для этого можно воспользоваться тем фактом, что определенные пользователем приведения типов используются только один раз, а встроенные — многократно. Т.е. достаточно заставить компилятор выполнять на одно преобразование больше, чем нужно, и будут работать только встроенные преобразования:


Круто
Re[13]: sizeof(array) in template
От: Владик Россия  
Дата: 20.02.03 10:57
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

[...]

Ладно, VC6.0 побороли, а что теперь делать с борландом? 5-й вылетает с internal compiler error, 6-й ругается вот так:

Как все запущенно...
Re[13]: sizeof(array) in template
От: Denn  
Дата: 20.02.03 12:54
Оценка:
Здравствуйте, Андрей Тарасевич, Вы писали:

В общем так, почти на все, что мне показалось личным, не так понятым и т.п. Отвечать некогда. Извини.

АТ> про проблемы из-за
 static T_& ret();


Имелась в виду более серьезная проблема, относительно необходимости прописать специализацию для void.

Я потому и не спешил выкладывать свои решения, что это могло мешать другим идеям. И более лучшему решению было бы труднее возникнуть.

Сравнение типов: с полпинка можно и по другому

template <class T>
 struct Type2Type {
        typedef T OriginalType;
 };

template <class T, class U>
 class TypeIdentity2 {
            static YES   checkit(Type2Type<T>);
            static NO    checkit(...);
        public:
            enum { value = sizeof(checkit(Type2Type<U>())) == sizeof(YES) };
 };


Жду критики, за которую всегда спасибо!!!
Re[13]: sizeof(array) in template
От: Андрей Тарасевич Беларусь  
Дата: 20.02.03 16:30
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:

ПК>

ME>>Понятно, что Метод основан на стандартном неявном преобразовании массива к указателю.
ME>>А как быть с этим: <... использование типов, с определенным пользователем приведением к указателю ...>

ПК>А для этого можно воспользоваться тем фактом, что определенные пользователем приведения типов используются только один раз, а встроенные — многократно. Т.е. достаточно заставить компилятор выполнять на одно преобразование больше, чем нужно, и будут работать только встроенные преобразования:


ПК>
ПК>struct PointerShim
ПК>{
ПК>  PointerShim(const volatile void*);
ПК>};

ПК>template<typename T_> struct is_array_
ПК>{
ПК>  template <typename U_>
ПК>  static char (&is(U_* const*))[1];


Раз уж мы вспомнили про 'volatile', то тогда и тут тоже стоит сделать так

  template <typename U_>
  static char (&is(U_* const volatile*))[1];



ПК>  static char (&is(...))[2];
ПК>  static T_* ret();

ПК>  enum { value = sizeof(is(ret())) - 1 };
ПК>};
ПК> ...
Best regards,
Андрей Тарасевич
Re[13]: sizeof(array) in template
От: Андрей Тарасевич Беларусь  
Дата: 20.02.03 18:08
Оценка:
Как все уже, наверное, поняли, приведенный мною изначальный вариант "распознавателя массивов" на самом деле распознает не именно массивы, а типы, неявно приводимые к типу "указатель", но при этом сами указателями не являющиеся. Массивы являются лишь одним из примеров таких типов. Также в эту группу входят функциональные типы и пользовательские типы с переопределенным оператором приведения типа. Павел в своем сообщении успешно отсеял последние. Но вот функциональные типы по-прежнему проскальзывают сквозь слишком широкую дыру:

typedef void F();
cout << is_array<F>::value << endl;
Best regards,
Андрей Тарасевич
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.