compile time class member detection

Тема в разделе "LANGS.C", создана пользователем scf37, 29 мар 2007.

  1. scf37

    scf37 New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2007
    Сообщения:
    44
    Это вообще возможно?
    т.е. можно ли написать шаблон
    template<class T>
    class check { ...};
    такой, что
    check<Type>::value == 0, если не существует Type::my_method()
    check<Type>::value != 0, если существует Type::my_method()

    Зачем это надо: оптимизированная версия алгоритма для итераторов произвольного доступа(т.е. перегружающих operator+(int) ).
     
  2. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    Возможно, поможет __if_exists из vc8.
     
  3. scf37

    scf37 New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2007
    Сообщения:
    44
    хорошо, но совсем уж непереносимо...
     
  4. Ustus

    Ustus New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2005
    Сообщения:
    834
    Адрес:
    Харьков
    scf37
    А оно все будет непереносимо. Такой подход характерен для LISP/PROLOG, а C++ - язык со строгой типизацией на стадии компиляции, поэтому стандарт такие финты осуждает.

    Расскажи подробнее, чего хочешь добиться, возможно есть менее изуверские методы, чем ран-тайм-чек :)
     
  5. scf37

    scf37 New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2007
    Сообщения:
    44
    не рантайм, а времени компиляции)
    template<class Iterator>
    void update_hash(Iterator begin, Iterator end);

    Например, алгоритм сам по себе работает со словами (16 бит), а итератор - байтовый
    В случае итераторов с последовательным доступом придётся копировать данные в некоторый буфер, а уже потом передавать "собранное" слово алгоритму.
    Если же итератор с произвольным доступом, то копирования можно избежать (если ++begin != end), используя выражения *begin и *(begin + 1) непосредственно в алгоритме.
    Не уверен, но имхо лучше избежать требования наличия конструктора копирования для итераторов, так что вариант:
    Iterator b1 = begin++;
    Iterator b2 = begin++;
    do_somth(b1, b2)
    не катит...
     
  6. RedLord

    RedLord Member

    Публикаций:
    0
    Регистрация:
    23 июн 2005
    Сообщения:
    183
    Адрес:
    Ukraine
    scf37

    IMHO, нужно что вроде этого:

    Код (Text):
    1. struct is_byte_iterator
    2. {
    3. };
    4.  
    5. struct is_word_iterator
    6. {
    7. };
    8.  
    9. struct iterator_byte
    10. {
    11.     typedef is_byte_iterator iter_type;
    12. };
    13.  
    14. struct iterator_word
    15. {
    16.     typedef is_word_iterator iter_type;
    17. };
    18.  
    19.  
    20. template<class Iterator>
    21. void update_hash_helper(Iterator begin, Iterator end, is_byte_iterator)
    22. {
    23.  
    24. }
    25.  
    26. template<class Iterator>
    27. void update_hash_helper(Iterator begin, Iterator end, is_word_iterator)
    28. {
    29.    
    30. }
    31.  
    32. template<class Iterator>
    33. void update_hash(Iterator begin, Iterator end)
    34. {
    35.     update_hash_helper(begin, end, Iterator::iter_type());
    36. }
    Если это итераторы STL, там есть iterator_category
     
  7. scf37

    scf37 New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2007
    Сообщения:
    44
    Ну если итераторы "свои" или стандартные, то и проблем никаких нет
    а мне хотелось бы сделать универсальный и (при наличии подходящих итераторов) быстрый интерфейс, например, для алгоритма подсчёта CRC
    типа:
    Код (Text):
    1. template<class iIt, class oIt>
    2. crc32(iIt begin, iIt end, oIt out);
    Конечно, желательно не доверять выбор реализации юзверю библиотеки.
     
  8. RedLord

    RedLord Member

    Публикаций:
    0
    Регистрация:
    23 июн 2005
    Сообщения:
    183
    Адрес:
    Ukraine
    scf37
    как определяются, подходящие итераторы?
     
  9. scf37

    scf37 New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2007
    Сообщения:
    44
    через специализации шаблонов
     
  10. RedLord

    RedLord Member

    Публикаций:
    0
    Регистрация:
    23 июн 2005
    Сообщения:
    183
    Адрес:
    Ukraine
    никто и не доверяет. в примере с update_hash - юзеры видят только ее.
    update_hash_helper - находится в кишках либы.

    в любом случае нужно определять категорию итератора (рандомный,т.д), если функции могут принимать итераторы векторов, списков, т.д (приведеный прием есть в STL - реализация distance)
     
  11. scf37

    scf37 New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2007
    Сообщения:
    44
    В том-то и вопрос - как определить категорию итератора :)
    Итераторы вовсе не обязаны поддерживать iterator_category
    Надо как-то различить итераторы произвольного и последовательного доступа. Основное различие - это наличие operator+ и operator[]
    Я хотел узнать, можно ли на этапе компиляции определить это различие или придётся смириться с судьбой и ждать стандартизации конструкции типа __if_exists ?
     
  12. RedLord

    RedLord Member

    Публикаций:
    0
    Регистрация:
    23 июн 2005
    Сообщения:
    183
    Адрес:
    Ukraine
    попробуй. если раскомментировать строки значение vv измениться

    Код (Text):
    1. struct Iter
    2. {
    3. //  int& operator[](size_t _N) const
    4. //  {
    5. //      return x;
    6. //  }  
    7.  
    8.     mutable int x;
    9. };
    10.  
    11.  
    12.  
    13. struct Dummy
    14. {
    15.         Dummy* operator[](size_t) const
    16.         {
    17.             return 0;
    18.         }          
    19. };
    20.  
    21.  
    22. template <class _Tp> struct helper2: _Tp, Dummy
    23. {
    24.  
    25.  
    26. };
    27.  
    28. template <class _U> struct helper
    29. {
    30.  
    31.     template <class _U1>
    32.     static char test(_U1*, int&);
    33.    
    34.     static char* test(void*, Dummy*);
    35.  
    36.     typedef helper2<_U> Type;
    37.     enum
    38.     {
    39.         value = (sizeof(test((Type*)0, Type()[0]))==sizeof(char))
    40.     };
    41.  
    42. };
    43.  
    44.  
    45.  
    46. int main()
    47. {
    48.     Iter q;
    49.     int vv = helper<Iter>::value;
    50.     return 0;  
    51. }
     
  13. RedLord

    RedLord Member

    Публикаций:
    0
    Регистрация:
    23 июн 2005
    Сообщения:
    183
    Адрес:
    Ukraine
    естественно код нужно облагородить.
    значение value вычисляется в compile-time :)
    сам сижу на VC6.0. страх и ужас для шаблонов :)
    если ты на VC8.0 - код резко упрощается. сходи на RSDN. там был пример слизаный из boost
     
  14. Nouzui

    Nouzui New Member

    Публикаций:
    0
    Регистрация:
    17 ноя 2006
    Сообщения:
    856
    RedLord, респектище...
     
  15. scf37

    scf37 New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2007
    Сообщения:
    44
    красиво.....
    уже минут 15 пытаюсь врубиться как оно работает :)
    Кстати, в Boost я ничего подобного не видел. Вроде они опираются на ключевые слова, специфичные для компилятора.

    Edit
    почему
    Код (Text):
    1. class A
    2. {
    3. public:
    4.     A & operator[](size_t x)
    5.     {
    6.         std::cout << "A\n";
    7.         return *this;
    8.     }
    9. };
    10.  
    11. class B
    12. {
    13. public:
    14.     B & operator[](size_t x)
    15.     {
    16.         std::cout << "B\n";
    17.         return *this;
    18.     }
    19. };
    20.  
    21. class C: public A, public B
    22. {
    23. };
    24.  
    25. int main()
    26. {
    27.     C c;
    28.     c[0];
    29.  
    30.     return 0;
    31. }
    работает, а
    Код (Text):
    1. class A
    2. {
    3. public:
    4.     A & operator1(size_t x)
    5.     {
    6.         std::cout << "A\n";
    7.         return *this;
    8.     }
    9. };
    10.  
    11. class B
    12. {
    13. public:
    14.     B & operator1(size_t x)
    15.     {
    16.         std::cout << "B\n";
    17.         return *this;
    18.     }
    19. };
    20.  
    21. class C: public A, public B
    22. {
    23. };
    24.  
    25. int main()
    26. {
    27.     C c;
    28.     c.operator1(0);
    29.  
    30.     return 0;
    31. }
    нет?
     
  16. Nouzui

    Nouzui New Member

    Публикаций:
    0
    Регистрация:
    17 ноя 2006
    Сообщения:
    856
    scf37
    банально.. если в <class _U> нет оператора [], используется оператор из Dummy, а если есть - из самого _U. Далше все основанно на преобразовании типов, но вот это, пожалуй, самый узкий момент..
    все равно, я даже не подозревал, что это возможно.. ))
     
  17. scf37

    scf37 New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2007
    Сообщения:
    44
    Неее, самый узкий - это почему operator[] не ambigious
    Остальное хорошо освещено Александреску в его культовой книжке...
     
  18. RedLord

    RedLord Member

    Публикаций:
    0
    Регистрация:
    23 июн 2005
    Сообщения:
    183
    Адрес:
    Ukraine
    scf37
    ambigious - online test Comeau так и сказал. ему я доверяю больше
    VC8.0 - переживал код.
     
  19. scf37

    scf37 New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2007
    Сообщения:
    44
    ещё интереснее:
    edit: проверил под VC6 и VC2005
    Код (Text):
    1.     C c;
    2.     c[0]; //нормально
    3.     c.operator[](0); //ambigious
    Тогда почему твой код работает? Фактически, ты делаешь то же самое - потомка от двух классов, каждый из которых может иметь operator[]
    А компилятор берёт operator[]() из первого попавшегося класса вместо того, чтобы ругаться.
     
  20. scf37

    scf37 New Member

    Публикаций:
    0
    Регистрация:
    29 мар 2007
    Сообщения:
    44
    RedLord
    Проверил под gcc 3.4.5 (mingw)
    Твой код там не работает... Похоже, причина в очень удачном баге MS C++ compiler, который не считает operator[] ambigious при краткой форме его вызова (см. предыдущий пост)

    edit: я не нашёл в стандарте(2003) каких-либо оговорок о "member name lookup" для операторных методов при множественном наследовании....