Evening, Andrei. Andrei Sosnin <[EMAIL PROTECTED]> 01:39 11/1/2003 wrote:
>> AS> В С++ эти элементы имеют определенные типы! Они, правда, подводятся >> AS> под шаблоны, но проверка типов там строгая, и трюки с void * там не >> AS> пройдут - придется применять специальные операторы-функции: >> AS> static_cast или dynamic_cast! Вот точное, концептуальное определение >> AS> данной функции (из STL): >> AS> template<class In, class Op> Op for_each( In first, In last, Op >> f){ >> AS> while (first != last) f(*first++); >> AS> return f; >> AS> } >> Вопрос: где зафиксирована информация о том, что f должна принимать >> аргумент того же типа, который имеет (*first++)? AS> В определении Op (класса объекта f). [skip общие сведения об итератора, операторах ++ и *] AS> Значение элемента всегда имеет строго определенный тип. В приведенном AS> ниже примере *(lc.begin()) будет иметь тип Club, так как lc.begin() AS> указывает на первый элемент списка lc, состоящего из объектов типа AS> Club. Вот именно. Всегда будет иметь _строго_ _определенный_ тип. А как насчет _произвольного_ типа, главное, чтобы он совпадал с типом аргумента функции f, который тоже _произвольный_? Как сделать hard-coded решение на шаблонах для конкретной задачи - мне понятно. Мне также понятно, как можно возвести это решение в ранг "универсального"/"библиотечног", обвешав его "своими", "удобными" реализациями контейнеров, итераторов и т.п. (по этому пути пошел STL). Мне непонятно, как заставить это решение работать в самом общем случае. Более того - я уверен, что реализовать такое решение невозможно. AS> Например (из "Языка программирования С++"): [skip пример со строго указанными hardcoded типами] >> И где же ответ на мои вопросы? Я повторю: >> 1)Каким образом происходит проверка того, что function_obj принимает аргумент >> именно того типа, который содержится в списке? AS> Это уже компетенция компилятора, я думаю... ;-) То есть компилятор AS> ДОЛЖЕН проверять это, и он это делает. Это провеяет модуль STL AS> (Standard Templates Library), который "инстанцирует" из шаблона list AS> классы вида list<int>, list<MyClass>, ... Если ты берешь объект AS> my_list класса list<MyClass> и пытаешься сделать с ним вот это: AS> for_each(my_list.begin(), my_list.end(), addvaluesbyone()); AS> И при этом класс addvaluesbyone не перегружает оператор () или этот AS> перегруженный оператор не принимает объекты типа MyClass, а только int AS> или float, или user_defined, то будет выдана ошибка компиляции. Вот. А если функция принимает, к примеру, аргумент типа ConcreteSuperclassOfMyClass - будет ли ошибка или нет? Если нет - то правильно ли это? :) Я считаю, что это - неправильно, приводит к трудноловимым ошибкам и костылям. >> 2)Этот вопрос я сформулировал неверно. Постараюсь изменить. Есть ли способ >> сделать type-safe композицию двух произвольных функций? >> Т.е. написать функцию compose типа >> forall c a b. (b -> c) -> (a -> b) -> a -> c >> которая реализует композицию фунций (в том смысле, в котором это >> определено >> в математике, (compose f g)(x) = f(g(x))) >> Сколько строк кода на это потребуется? Что будет с проверкой типов? >> AS> Ах вот оно что! Ты хочешь реализацию сложной функции f(g(x))? AS> Вот реализация на С: AS> float f(float (*g_func)(float x)){ AS> float a = (*g_func)(x); AS> return sin(sqrt(a)); AS> } AS> float g(float x){ AS> return do_something(x); AS> } AS> Совершенно type-safe. Да-да. Машина может быть любого цвета, лишь бы этот цвет был черным (с) компания Форд. Ты не замечаешь разницы между тем, что написал я, и тем, что написал ты? У меня функция f имеет тип "отображение из X в Y", функция g имеет тип "отображение из Y в Z", результат compose имеет тип "отображение из X в Z", где X,Y,Z - _произвольные_ типы. Главное, чтобы тип результата f и аргумента g совпадал. Как мне при помощи твоего "решения" скомбинировать функции из float в string и из string в int ? AS> Другое дело, что с такой специлизацией это в AS> универсальную библиотеку С не в ставишь, но для конкретных мелких AS> задач вполне подойдет. Т.е. не Иванов, а Рабинович, не в лотерею, а в казино, не Волгу, а Мерседес, и не выиграл, а проиграл? :) Как по мне - соверешенно не похоже на "да! это можно сделать и на С!". AS> На С++ это можно записать совершенно также, но можно применить и ООП-метод. Увы, скорее "так же", а не "также". Так же плохо. AS> Например: AS> template <class T> AS> class composite_func { AS> T rep; [skip] AS> T operator()(T arg){ AS> //do something with arg using g AS> return arg; AS> } AS> }; AS> Теперь composite_func можно использовать как обычную функцию. Только AS> инстанциация должна проходить так, например: composite_func<float>(); Ничего, что у тебя получаются только функции из X в X? :) AS> Наконец, замечу, что С++ все-таки язык системного программирования, и AS> он оптимизирован именно под системные нужды - скорость, AS> низкоуровневость (привязанность к системным особенностям), ... Я не AS> могу сказать, что он лучше всех, сверх-универсален, "и ваще". :-) Этого никто и не говорил. И не просил доказать. Просто были продемонстрированы (мной) некие принципы, которые, по моему мнению, делают ФЯ более предпочтительными средствами для программирования, чем императивные языки. Было сказано - "на С++ можно все то же самое". Из твоей последней фразы следует, что где-то по пути предмет спора был волшебным образом подменен на какой-то другой, мне неизвестный ... :) AS> Еще я советую где-нибудь достать христоматийную книгу от Бьерна AS> Страуструпа "Язык программирования С++". У меня дома лежит русский AS> перевод от издательства "БИНОМ" 1999 года. Оригинал был издан AS> Addison-Wesley Longman. Очень полезная книга для тех кто сомневается в AS> достоинствах С++ или плохо с ним знаком. Да-да.... А кто до сих пор сомневается - плохо ее читал, так? :) -- Dmitry Astapov //ADEpt E-mail: [EMAIL PROTECTED] GPG KeyID/fprint: F5D7639D/CA36 E6C4 815D 434D 0498 2B08 7867 4860 F5D7 639D