Это вообще возможно? т.е. можно ли написать шаблон template<class T> class check { ...}; такой, что check<Type>::value == 0, если не существует Type::my_method() check<Type>::value != 0, если существует Type::my_method() Зачем это надо: оптимизированная версия алгоритма для итераторов произвольного доступа(т.е. перегружающих operator+(int) ).
scf37 А оно все будет непереносимо. Такой подход характерен для LISP/PROLOG, а C++ - язык со строгой типизацией на стадии компиляции, поэтому стандарт такие финты осуждает. Расскажи подробнее, чего хочешь добиться, возможно есть менее изуверские методы, чем ран-тайм-чек
не рантайм, а времени компиляции) 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) не катит...
scf37 IMHO, нужно что вроде этого: Код (Text): struct is_byte_iterator { }; struct is_word_iterator { }; struct iterator_byte { typedef is_byte_iterator iter_type; }; struct iterator_word { typedef is_word_iterator iter_type; }; template<class Iterator> void update_hash_helper(Iterator begin, Iterator end, is_byte_iterator) { } template<class Iterator> void update_hash_helper(Iterator begin, Iterator end, is_word_iterator) { } template<class Iterator> void update_hash(Iterator begin, Iterator end) { update_hash_helper(begin, end, Iterator::iter_type()); } Если это итераторы STL, там есть iterator_category
Ну если итераторы "свои" или стандартные, то и проблем никаких нет а мне хотелось бы сделать универсальный и (при наличии подходящих итераторов) быстрый интерфейс, например, для алгоритма подсчёта CRC типа: Код (Text): template<class iIt, class oIt> crc32(iIt begin, iIt end, oIt out); Конечно, желательно не доверять выбор реализации юзверю библиотеки.
никто и не доверяет. в примере с update_hash - юзеры видят только ее. update_hash_helper - находится в кишках либы. в любом случае нужно определять категорию итератора (рандомный,т.д), если функции могут принимать итераторы векторов, списков, т.д (приведеный прием есть в STL - реализация distance)
В том-то и вопрос - как определить категорию итератора Итераторы вовсе не обязаны поддерживать iterator_category Надо как-то различить итераторы произвольного и последовательного доступа. Основное различие - это наличие operator+ и operator[] Я хотел узнать, можно ли на этапе компиляции определить это различие или придётся смириться с судьбой и ждать стандартизации конструкции типа __if_exists ?
попробуй. если раскомментировать строки значение vv измениться Код (Text): struct Iter { // int& operator[](size_t _N) const // { // return x; // } mutable int x; }; struct Dummy { Dummy* operator[](size_t) const { return 0; } }; template <class _Tp> struct helper2: _Tp, Dummy { }; template <class _U> struct helper { template <class _U1> static char test(_U1*, int&); static char* test(void*, Dummy*); typedef helper2<_U> Type; enum { value = (sizeof(test((Type*)0, Type()[0]))==sizeof(char)) }; }; int main() { Iter q; int vv = helper<Iter>::value; return 0; }
естественно код нужно облагородить. значение value вычисляется в compile-time сам сижу на VC6.0. страх и ужас для шаблонов если ты на VC8.0 - код резко упрощается. сходи на RSDN. там был пример слизаный из boost
красиво..... уже минут 15 пытаюсь врубиться как оно работает Кстати, в Boost я ничего подобного не видел. Вроде они опираются на ключевые слова, специфичные для компилятора. Edit почему Код (Text): class A { public: A & operator[](size_t x) { std::cout << "A\n"; return *this; } }; class B { public: B & operator[](size_t x) { std::cout << "B\n"; return *this; } }; class C: public A, public B { }; int main() { C c; c[0]; return 0; } работает, а Код (Text): class A { public: A & operator1(size_t x) { std::cout << "A\n"; return *this; } }; class B { public: B & operator1(size_t x) { std::cout << "B\n"; return *this; } }; class C: public A, public B { }; int main() { C c; c.operator1(0); return 0; } нет?
scf37 банально.. если в <class _U> нет оператора [], используется оператор из Dummy, а если есть - из самого _U. Далше все основанно на преобразовании типов, но вот это, пожалуй, самый узкий момент.. все равно, я даже не подозревал, что это возможно.. ))
Неее, самый узкий - это почему operator[] не ambigious Остальное хорошо освещено Александреску в его культовой книжке...
ещё интереснее: edit: проверил под VC6 и VC2005 Код (Text): C c; c[0]; //нормально c.operator[](0); //ambigious Тогда почему твой код работает? Фактически, ты делаешь то же самое - потомка от двух классов, каждый из которых может иметь operator[] А компилятор берёт operator[]() из первого попавшегося класса вместо того, чтобы ругаться.
RedLord Проверил под gcc 3.4.5 (mingw) Твой код там не работает... Похоже, причина в очень удачном баге MS C++ compiler, который не считает operator[] ambigious при краткой форме его вызова (см. предыдущий пост) edit: я не нашёл в стандарте(2003) каких-либо оговорок о "member name lookup" для операторных методов при множественном наследовании....