LINUX.ORG.RU

[STL][C++] чем грозит частичная спецификация less без наследования binary_function?

 ,


0

2

У меня есть некий набор своих параметризованных классов, для которых определены операции сравнения. Для использования этих классов в качестве ключей map надо использовать другие операции сравнения (те которые определены неоднозначны). Напрашивается частично специфицировать структуру less, я могу сделать напр так

template<int D> struct A{ ... };

namespace std{
	template<class T> struct less;
	template<int D> struct less<A<D> > {
		bool operator()(const A<D>& x, const A<D>& y) const {...} 
	};
};

А в STL вроде так

template <class T>
struct less : binary_function<T, T, bool> {
    bool operator()(const T& x, const T& y) const { return x < y; } 
};
и в моих примерах все работает. Но возникает вопрос - могут ли вылезти какие то праблы в дальнейшем, связанные с тем что я не отнаследовался от binary_function? Мне сразу тащить STL не хочется, я им в общем не так часто пользуюсь, пусть уж он приходит только когда нужен map и т.д.;-)

★★★★★

Ответ на: комментарий от JackYF

Во первых у меня уже есть нек-е кол-во кода, где map указан без 3го параметра, и править его не хочется (в свое время пришлось для этого специально вводить однозначные операции сравнения, они неск противоестественны но я не думал что естественные когда нить понадобятся - но вот сейчас таки понадобились;-)).

Во вторых если юзер (или я сам) забудут этот третий параметр когда нить потом, то последствия будут нехорошие, причем в рантайме, и ловить эту ошибку будет очень непросто.

AIv ★★★★★
() автор топика

Но возникает вопрос - могут ли вылезти какие то праблы в дальнейшем, связанные с тем что я не отнаследовался от binary_function?

для ответа на этот вопрос достаточно посмотреть определение std::binary_function

template <class Arg1, class Arg2, class Result>
  struct binary_function {
    typedef Arg1 first_argument_type;
    typedef Arg2 second_argument_type;
    typedef Result result_type;
  };

всего лишь пара typedef :) сделано это для того чтобы не набивать их вручную каждый раз, так что пока никто не «зохочет» их подёргать - ничего не будет, а если захочет «компилятур» ему об этом быстро напомнит

если работает и всё устраивает - думаю можно не париться :)

shty ★★★★★
()
Ответ на: комментарий от AIv

Я честно говоря не знаю... а разве стандарт явно запрещает это делать?;-)

не запрещает, но кто знает на какие подводные грабли на гиромагнитной подвеске можно вот так нарваться

shty ★★★★★
()
Ответ на: комментарий от AIv

Аргумент принят.

Контраргумент: у тебя в проекте less< T > будет делать одно, а T < T — другое, я так понимаю. С этим ты тоже можешь поиметь неочевидных проблем.

Я бы T < T сделал «нормальным», а для «однозначные операции сравнения, они неск противоестественны» сделал отдельную функцию.

JackYF ★★★★
()
Ответ на: комментарий от shty

> не запрещает, но кто знает на какие подводные грабли на гиромагнитной подвеске можно вот так нарваться

Дык я потому и спрашиваю - я по stl не специалист.

AIv ★★★★★
() автор топика
Ответ на: комментарий от JackYF

> Контраргумент: у тебя в проекте less< T > будет делать одно, а T < T — другое, я так понимаю. С этим ты тоже можешь поиметь неочевидных проблем.

less используется только через stl, для однозначного упорядочивания объектов, и только тогда, когда их надо упорядочивать. Во всех остальных случаях операции сравнения служат совсем не для упорядочивания (поскольку напр. упорядочивать D-мерные вектора в декартовом пр-ве идея довольно странная).

И мне б как раз очень хотелось, что бы stl работал по умолчанию правильно, а уж если кто попробует всунуть явно less вместо оператора сравнения двух векторов - это будут его проблемы.

AIv ★★★★★
() автор топика
Ответ на: комментарий от shty

ну, если говорить за себя, то я бы не стал делать вот так...

Я бы тоже, но:

error: specialization of ‘template<class _Tp> struct std::less’ in different namespace
/usr/include/c++/4.4/bits/stl_function.h:226: error:   from definition of ‘template<class _Tp> struct std::less’
AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

>поскольку напр. упорядочивать D-мерные вектора в декартовом пр-ве идея довольно странная

эээ, ради интереса - а что делает T < T в твоём проекте на T == D-мерный вектор?

JackYF ★★★★
()
Ответ на: комментарий от AIv

> ну, если говорить за себя, то я бы не стал делать вот так...

Я бы тоже, но:

error: specialization of ‘template<class _Tp> struct std::less’ in different namespace
/usr/include/c++/4.4/bits/stl_function.h:226: error:   from definition of ‘template<class _Tp> struct std::less’

error: дуло пушки не влезает в рот: (a)bort, (r)etry, (о)ткрыть рот пошире?

я к тому что если что-то куда не подходит, это ещё не повод фиксить положение сомнительными методами, хотя это возможно моя персональная паранойя :)

shty ★★★★★
()
Ответ на: комментарий от JackYF

a < b если a[i]<b[i] для всех i. Я двумя векторами могу выделить прямоугольную область, очень лаконично пишется и очень удобно.

У меня еще были индексы (D-мерные целочисленные вектора адресующие ячейку в D-мерном массиве), вот их я сравнивал однозначно и сувал в map. Но из за этого возникает некая путаница + выяснилось что области в массиве тоже надо выделять + вектора тоже надо пихать в map...

AIv ★★★★★
() автор топика
Ответ на: комментарий от shty

> error: дуло пушки не влезает в рот: (a)bort, (r)etry, (о)ткрыть рот пошире?

А вдруг это не пушка а яблочный рулет? Вот сейчас придет кто нить и скажет - да, это вкусно... (или придет кто нить без головы и скажет - 6дюймовый фугас;-)) Ну ждем-с...

AIv ★★★★★
() автор топика

Какой ужас !

Я так понял проблема возникла по причине кривизны архитектуры и решать её надо путем исправления архитектуры. Не стоит вешать одни костыли на другие.

Вообще надо десять раз подумать, прежде чем засовывать в map-ы что-то отличное от базовых примитивов. В большинстве случаев вместо объекта, можно засунуть в map указатель на объект.

В общем я считаю саму идею less-костыля неудачной. Лучше собраться с духом и заняться рефакторингом кода, так, чтобы код принял логичный и интуитивно понятный вид. Можешь поверить мне, потом сам себе скажешь спасибо.

А то, что «уже много написано», это не более чем отговорки.

pathfinder ★★★★
()
Ответ на: комментарий от Reset

мне, простите, интересно чем плохо предложенное решение, а не то как-надо-делать-чтобы-соблюсти-целебат.

AIv ★★★★★
() автор топика
Ответ на: Какой ужас ! от pathfinder

> Вообще надо десять раз подумать, прежде чем засовывать в map-ы что-то отличное от базовых примитивов. В большинстве случаев вместо объекта, можно засунуть в map указатель на объект.

Забавно. А зачем тогда ребятки озаботились созданием того самого less? И какой смысле сувать в мап указатель, если объект вычислен в ре-те какой то хитрой операции а в мап уже лежит указатель на такой же объект но с другим адресом? Это тогда не мап а список получается...

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

можете привести хотя бы одну потенциальную опасность less-костыля?

http://ru.wikipedia.org/wiki/KISS_(принцип)

Сама по себе зашаблоненность кода, это не хорошо, а шаблоны-костыли это вообще песец.

Для меня например тот код совершенно не очевиден. Я бы не назвал такие конструкции интуитивно понятными.

pathfinder ★★★★
()
Ответ на: комментарий от AIv

Забавно. А зачем тогда ребятки озаботились созданием того самого less?

Если на стене висит красная кнопка, то это не значит, что надо обязательно на неё нажимать. Если ты не понимаешь что это и для каких целей создавалось, то лучше не трогать. Откуда уверенность, что для тебя такой фокус не аукнется где-то ещё? Ты так хорошо знаешь потроха STL? Или где-то в стандарте вычитал, что так можно делать?

pathfinder ★★★★
()
Ответ на: комментарий от pathfinder

Если для Вас какой то код неочевиден и интуитивно непонятен, это совершенно не означает что он плох. Например квантовая механика интуитивно совершенно неясна, тем не менее ничего лучшего для описания некоторых вещей пока что не придумано.

По ссылке я никаких аргументов не нашел, этим принципом сам постоянно пользуюсь и предложенное решение (как и вся архитектура проекта) ему очень четко следуют.

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

Если для Вас какой то код неочевиден и интуитивно непонятен, это совершенно не означает что он плох.

Для меня такой код именно плох. Другое дело, что бывают безвыходные ситуации, когда ты не видишь иных путей решения проблемы. Я не думаю, что у вас там безвыходная ситуация. Скорее всего вы там что-то написали, потом пришли к выводу, что так не прокатит, но возвращаться назад и переделывать уже сделанное не хочется. Вот и думаете как бы повесить костыль и оставить старый код «как есть».

pathfinder ★★★★
()
Ответ на: комментарий от pathfinder

Хорошо, я перефразирую - если для Вас код неочевиден и непонятен, это не значит что он неочевиден и непонятен для всех остальных;-)

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

Хорошо, я перефразирую - если для Вас код неочевиден и непонятен, это не значит что он неочевиден и непонятен для всех остальных;-)

Ты хочешь сказать, что код вида:

template<int D> struct A{ ... };

namespace std{
   template<class T> struct less;
   template<int D> struct less<A<D> > {
      bool operator()(const A<D>& x, const A<D>& y) const {...} 
   };
};
будет понят среднестатистическим плюсовым программистом?

pathfinder ★★★★
()
Ответ на: комментарий от pathfinder

Среднестатистическому плюсовому программисту (не знаю что это за зверь, но допустим человек знакомый с мапами) на этот код смотреть вообще не зачем - ему важно что например класс map<A,int> работает.

Или ты думаешь что код map-a или istream-a понятен этому самому программисту?;-)

AIv ★★★★★
() автор топика
Ответ на: комментарий от pathfinder

И если он этого не понимает, как он поймет что надо писать map<A,int,myless<A> >??? А когда он забудет это написать (покольку он типа тупой и не понимает зачем это надо писать), как он поймет отчего у него в рантайме все грохнулось?

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

И если он этого не понимает, как он поймет что надо писать map<A,int,myless<A> >

Он может и не поймет, но если ты будешь использовать myless явно, он начнет искать в документации информацию о третьем параметре. А если не будешь, то либо A будет классом, полностью адаптированным для работы с map (тогда не говори, у него неправильные операторы сравнения), либо ССЗБ.

Изначальный вариант представляет собой некое подобие side effect, неявным образом изменяющее поведение map<A,int>, тем более, что оператор сравнения ты уже явном виде переопределил, что приведет к дополнительной путанице.

pathfinder ★★★★
()
Ответ на: комментарий от AIv

можно проверить совпадает ли тип первого парамтра с вашим специфичным типом если да то проверить не равен ли тип третьего параметра стандартному компаратору если равен останавливать компиляцию

как нить так

template<class A,,class comp = less<A>>
class map
{
typedef char buf[is_same<A, YOUR_TYPE>::value ? is_same<comp, less<A>::value ? -1 : 1 : 1];
};

anonymous
()
Ответ на: комментарий от pathfinder

Пффф... начнет искать в документации? Много ты видел таких пользователей, которые читают документацию?

В общем контраргументы у тебя ИМНО неубедительные - «ты должен оставить люк открытым, но обозначить его флажками на карте, что б все знали что люк там есть». Я предпочитаю люки закрывать, а если кто его откроет и свалится туда - вот он и есть ССЗБ.

Погляди на это по другому - есть две разных возможности сравнения, одна реализована через операторы и применяется для проверок границ, другая реализована через less и применяется для упорядочивания. Использовать less для проверок границ неестественно, использовать операторы для упорядочивания естественно но упорядочивание нигде кроме stl не нужно, а stl использует less.

AIv ★★★★★
() автор топика
Ответ на: комментарий от anonymous

> можно проверить совпадает ли тип первого парамтра с вашим специфичным типом

Э... а как я влезу в map?;-) И главное - зачем, что бы типа был чище дизайн?;-)

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

Я предпочитаю люки закрывать

В том, то и проблема, что ты люки открываешь. Скрытые эффекты и не очевидное поведение - очень опасная вещь.

Использовать less для проверок границ неестественно,

Использовать операторы сравнения для векторов (я так понял у тебя там вектора) неестественно.

pathfinder ★★★★
()
Ответ на: комментарий от pathfinder

Давайте обсуждать омаров с теми, кто их ел?

Ты не знаешь ничего о специфике решаемой мною задачи, как ты можешь говорить о том что естественно и что неестественно? Ох уж этот ЛОР;-)

AIv ★★★★★
() автор топика
Ответ на: комментарий от AIv

«все должно быть просто насколько это возможно но не проще» - энштейн если он не знает что для мапа юзается лесс для компаратора тогда пусть огребает ошибки пока не наберется опыта это лучше чем мусорить в std пространстве

anonymous
()
Ответ на: комментарий от AIv

>Ты не знаешь ничего о специфике решаемой мною задачи

Странно ожидать, спрашивая у совершенно незнакомых людей на форуме, что они будуть знать специфику. Кто её может знать, кроме коллег?

JackYF ★★★★
()
Ответ на: комментарий от AIv

Ты не знаешь ничего о специфике решаемой мною задачи

Ну так расскажи, что ты там с чем сравниваешь и зачем засовываешь всю эту фигню в map.

Должно быть что-то одно из двух, либо ты балуешься со переопределением операторов сравнения и тогда у тебя будет класс несовместимый с контейнерами STL, либо ты переопределяешь операторы класса с учетом всех требований, предъявляемых библиотекой STL.

Либо, либо. Попытка занять промежуточную позицию и начать шаманить с шаблонами может привести к проблемам.

pathfinder ★★★★
()
Ответ на: комментарий от AIv

ясно почему так любят C++ этож если его знать можно холиварить часами над «лучшей» реализацией какой нить хрени

anonymous
()
Ответ на: комментарий от pathfinder

> Либо, либо. Попытка занять промежуточную позицию и начать шаманить с шаблонами может привести к проблемам.

КАКИМ ИМЕННО ПРОБЛЕМАМ? Можно конкретики (примеры конкретных проблем) вместо баю-баюшки-баю-не-ложися-на-краю?;-) Я ведь об этом (КАКИЕ КОНКРЕТНЫЕ ПРОБЛЕМЫ МЕНЯ ЖДУТ ПРИ ТАКОМ ПЕРЕОПРЕДЕЛЕНИИ less) и спрашиваю с самого начала?

Пока только эмоции - «не сори в std, это не кошерно, это не халально, и вообще отойди от шаблонов»!

Ну так расскажи, что ты там с чем сравниваешь и зачем засовываешь всю эту фигню в map.

Ты хочешь присоединится к проекту на общ началах (поскоку денег у нас нету)? Велкам! aivanov(злая собака)keldysh.ru, пиши, обсудим;-)

AIv ★★★★★
() автор топика
Ответ на: комментарий от JackYF

> Странно ожидать, спрашивая у совершенно незнакомых людей на форуме, что они будуть знать специфику. Кто её может знать, кроме коллег?

А я и не ожидаю. Но я ожидаю от ВМЕНЯЕМЫХ незнакомых людей, что не познакомившись со спецификой они не будут кидаться ссаными тряпками - «так делать низя ни в коем случае»!;-)

AIv ★★★★★
() автор топика

За влезание в std теоретически могут дать по рукам компиляторы. Право у них такое есть, так что если не хочешь в будущем однажды оказаться на скамейке дураков рядом с adobe - в неймспейс std лучше не лезть. Не вижу повода бояться std::binary_function, раз уж пользуешься map. Да и вообще стандартная библиотека на то и стандартная, чтоб её не избегать.

И да, не слушай всяких плюсофобов, которые тебя отговаривают пользоваться std::map. Он рулез и легко переваривает способ, которым ты его используешь, указатели тут не нужны пока не упрёшься в производительность.

А вот operator<() с не очевидным поведением - это таки недочёт. Всё-таки люди ожидают, что operator<() ведёт себя так-же, как и с интами, например, т.е. без сюрпризов и недомолвок.

legolegs ★★★★★
()
Ответ на: комментарий от legolegs

> За влезание в std теоретически могут дать по рукам компиляторы

Я не очень понимаю за что тут бить, тем более что я не первый такой http://en.wikibooks.org/wiki/More_C++_Idioms/Non-throwing_swap

А вот operator<() с не очевидным поведением - это таки недочёт. Всё-таки люди ожидают, что operator<() ведёт себя так-же, как и с интами, например, т.е. без сюрпризов и недомолвок.

См выше - для таких объектов вообще сравнение вводится неоднозначно.

AIv ★★★★★
() автор топика
Ответ на: комментарий от ratatosk

> Ничего страшного в namespace std{...} нету. std::swap только так и переопределяется.

Во, спасибо! Верной дорогой значит идем;-)

AIv ★★★★★
() автор топика
Ответ на: комментарий от legolegs

За влезание в std теоретически могут дать по рукам компиляторы

расширять std нельзя, специализировать - можно; нарушений стандарта нет, за что давать по рукам?

А вот operator<() с не очевидным поведением - это таки недочёт

а вот за такое надо отрывать конечности, конечно, с мясом

jtootf ★★★★★
()
Ответ на: комментарий от jtootf

Спасибо маэстро, Вам я верю!;-)

fixed.

Всем еще раз спасибо за увлекательное обсуждение, тема закрыта.

AIv ★★★★★
() автор топика
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.