Здравствуйте, tors, Вы писали:
T>struct TInfoEx T>{ T> TInfo Info; T> String Name; T>};
T>set<TInfoEx> InfoEx;
T>TInfoEx inf; T>. T>. T>. T>InfoEx.insert(inf);
T>operator< not implemented in type TInfoEx for arguments of the same type
T>вероятно нужно реализовать operator< для этой структуры и вложенных в нее структур?
Да. Или предоставить set-у бинарный предикат, определяющий отношение порядка. T>как это сделать — пример плиз
Это сильно зависит от природы TInfoEx, и от того, что побудило тебя использовать именно set, а не, скажем, vector.
Пример, конечно можно привести, но сколько в нем смысла — большой вопрос
inline bool operator < (const TInfoEx& l, const TInfoEx& r)
{
return l.Name < r.Name;//Это если operator < определен для твоего String
}
Любите книгу — источник знаний (с) М.Горький
Re: Непонятки с set
От:
Аноним
Дата:
19.04.06 14:08
Оценка:
Здравствуйте, tors, Вы писали:
T>struct TInfoEx T>{ T> TInfo Info; T> String Name; T>};
T>set<TInfoEx> InfoEx;
T>TInfoEx inf; T>. T>. T>. T>InfoEx.insert(inf);
T>operator< not implemented in type TInfoEx for arguments of the same type
T>вероятно нужно реализовать operator< для этой структуры и вложенных в нее структур? T>как это сделать — пример плиз
лучше специализировать std::less<>():
bool std::less<TInfoEx>::operator()(const TInfoEx& _X, const TInfoEx& _Y) const
{
// тут нужно решить что является ключом в TInfoExreturn std::less<TInfo>()(_X.Info, _Y.Info);
}
Здравствуйте, Аноним, Вы писали:
T>>вероятно нужно реализовать operator< для этой структуры и вложенных в нее структур? T>>как это сделать — пример плиз
А>лучше специализировать std::less<>():
Почему?
Re[3]: Непонятки с set
От:
Аноним
Дата:
19.04.06 14:19
Оценка:
Здравствуйте, DigitalGuru, Вы писали:
DG>Здравствуйте, Аноним, Вы писали:
T>>>вероятно нужно реализовать operator< для этой структуры и вложенных в нее структур? T>>>как это сделать — пример плиз
А>>лучше специализировать std::less<>():
DG>Почему?
По-моему это логичнее, потому что работаем мы в std, вот и пользуемся средствами оттуда. И ещё, в определении самого класса std::set указывается предикат, который используется для сравнения ключей. Обычно это и есть std::less. То что он дублирует operator <, это в общем-то никого волновать не должно
Здравствуйте, Аноним, Вы писали:
T>>>>вероятно нужно реализовать operator< для этой структуры и вложенных в нее структур? А>>>лучше специализировать std::less<>(): DG>>Почему? А>По-моему это логичнее, потому что работаем мы в std, вот и пользуемся средствами оттуда. И ещё, в определении самого класса std::set указывается предикат, который используется для сравнения ключей. Обычно это и есть std::less. То что он дублирует operator <, это в общем-то никого волновать не должно
Если мы определяем operator<, то у нас будет одинаково работать код, использующий operator<, и код, использующий std::less. Если мы только специализируем std::less, то код, использующий operator<, не будет компилироваться, а код, использующий std::less, будет работать. Если же мы специализируем std::less, а потом кто-нибудь определит ещё operator<, то код, использующий operator<, и код, использующий std::less, будут работать по-разному, что не удовлетворяет принципу наименьшего изумления. Поэтому лучше будет определить operator< и не трогать std::less.
Re[5]: Непонятки с set
От:
Аноним
Дата:
20.04.06 09:13
Оценка:
Здравствуйте, Centaur, Вы писали:
C>Если мы определяем operator<, то у нас будет одинаково работать код, использующий operator<, и код, использующий std::less. Если мы только специализируем std::less, то код, использующий operator<, не будет компилироваться, а код, использующий std::less, будет работать. Если же мы специализируем std::less, а потом кто-нибудь определит ещё operator<, то код, использующий operator<, и код, использующий std::less, будут работать по-разному, что не удовлетворяет принципу наименьшего изумления. Поэтому лучше будет определить operator< и не трогать std::less.
operator < нужно определить сразу же за определением std::less<>, если размер проекта предполагает, что разные пользователи этой структуры могут его опредилить. Оператор, конечно же, вызывает std::less.
Без определения std::less и без знания, что он связан с operator <, разобраться как работает std::set будет сложно (смотря на его определение).
Само определение std::set требует std::less (или другого предиката) в качестве параметра. И святой долг пользователя этого класса так и сделать. Иначе — хаос, неразбериха Дополнительное определение operator < — это вынужденная мера, хотя и очень желательная.
Здравствуйте, Аноним, Вы писали:
А>operator < нужно определить сразу же за определением std::less<>, если размер проекта предполагает, что разные пользователи этой структуры могут его опредилить. Оператор, конечно же, вызывает std::less.
Дефолтный std::less уже реализован в терминах operator<. Зачем ставить всё с ног на голову?
Здравствуйте, Centaur, Вы писали:
C>Здравствуйте, Аноним, Вы писали:
А>>operator < нужно определить сразу же за определением std::less<>, если размер проекта предполагает, что разные пользователи этой структуры могут его опредилить. Оператор, конечно же, вызывает std::less.
Я — это Аноним
C>Дефолтный std::less уже реализован в терминах operator<. Зачем ставить всё с ног на голову?
Это ещё знать нужно, когда разбираешься с кодом. Определение только operator < усложняет код. А следующий абзац предыдущего поста — не аргумент?
Здравствуйте, Максим2006, Вы писали:
М>>>operator < нужно определить сразу же за определением std::less<>, если размер проекта предполагает, что разные пользователи этой структуры могут его опредилить. Оператор, конечно же, вызывает std::less.
C>>Дефолтный std::less уже реализован в терминах operator<. Зачем ставить всё с ног на голову? М>Это ещё знать нужно, когда разбираешься с кодом. Определение только operator < усложняет код.
Ни в малейшей степени. Средний программист на C++ знает, что std::set работает с operator<, если не указано иное.
М>А следующий абзац предыдущего поста — не аргумент?
М>>>Без определения std::less и без знания, что он связан с operator <, разобраться как работает std::set будет сложно (смотря на его определение).
Как работает std::set, нужно разбираться, смотря не на определение, а в стандарт, или в Страуструпа, или в Йозуттиса.
М>К тому же, что будет если кто-нибудь потом определит std::less также как operator < (о чём сетовали тут: http://www.rsdn.ru/Forum/Message.aspx?mid=1856924&only=1)?
Если у нас есть operator<, то вряд ли кому-то придёт в голову специализировать std::less, потому что любой код, использующий std::less, скомпилируется и будет использовать стандартную реализацию. Если же у нас будет специализация std::less, то кто-нибудь попробует написать код с использованием operator<, обломается и может пойти реализовывать его. И с большой вероятностью сделает не так, как в нашей специализации std::less. И тем более не будет реализовывать operator< через std::less, потому что знает, что по умолчанию делается наоборот.
Собственно говоря, всё это можно найти у Scott’а Meyers’а в Effetive STL, Item 42.
Здравствуйте, Centaur, Вы писали:
C>Здравствуйте, Максим2006, Вы писали:
М>>>>operator < нужно определить сразу же за определением std::less<>, если размер проекта предполагает, что разные пользователи этой структуры могут его опредилить. Оператор, конечно же, вызывает std::less.
C>>>Дефолтный std::less уже реализован в терминах operator<. Зачем ставить всё с ног на голову? М>>Это ещё знать нужно, когда разбираешься с кодом. Определение только operator < усложняет код.
C>Ни в малейшей степени. Средний программист на C++ знает, что std::set работает с operator<, если не указано иное.
А если человек не работал раньше с STL, новичок?
М>>>>Без определения std::less и без знания, что он связан с operator <, разобраться как работает std::set будет сложно (смотря на его определение).
C>Как работает std::set, нужно разбираться, смотря не на определение, а в стандарт, или в Страуструпа, или в Йозуттиса.
Согласен, хотя новичок, по опыту знаю, в код сначала лезет.
М>>К тому же, что будет если кто-нибудь потом определит std::less также как operator < (о чём сетовали тут: http://www.rsdn.ru/Forum/Message.aspx?mid=1856924&only=1)?
C>Если у нас есть operator<, то вряд ли кому-то придёт в голову специализировать std::less, потому что любой код, использующий std::less, скомпилируется и будет использовать стандартную реализацию. Если же у нас будет специализация std::less, то кто-нибудь попробует написать код с использованием operator<, обломается и может пойти реализовывать его. И с большой вероятностью сделает не так, как в нашей специализации std::less.
Так может оно и правильно? Если он сделает иначе, значит так оно и должно быть. Если он будет класть этот тип в сортируемый по std::less контейнер, то он должен будет вспомнить про std::less, который он видел рядом с этим типом.
C>И тем более не будет реализовывать operator< через std::less, потому что знает, что по умолчанию делается наоборот.
Если б он это знал, он бы как раз и реализовал operator < через std::less. Потому что реализовывать собственный вариант operator < он будет только в том случае,если не знает что делается по умолчанию.
C>Собственно говоря, всё это можно найти у Scott’а Meyers’а в Effetive STL, Item 42.
Очень интересный item. Спасибо за эту ссылку.
Только однозначно я не убедился в правильности этого подхода. Однако я и несколько разубедился в правильности своего подхода
В этом тексте очень много личного отношения к написанию кода, но объяснений очень мало. Кое с чем я там лично не согласен. Если откинуть все "нельзя", "делай так-то" и пр., то остаётся идея, что в библиотеке установлено такое правило использования сортирующих контейнеров, что туда передаётся либо собственный компоратор (при специфичном сравнении), либо определяется operator < (при обычном, напрашивающемся сравнении). И это является правилом только лишь на основании факта определения std::less по умолчанию. Типа у нас тут в std свои заморочки, свои механизмы работы, а ты сюда не суйся, у тебя свои методы должны быть. Что ж эта точка зрения мне ясна, но она не такая уж чёткая и очевидная, поэтому не понятно, почему не имеет право на существование другая точка зрения, когда рвётся связь по умолчанию между operator < и std::less? Почему я могу использовать одни объекты библиотеки, но не могу использовать другие? Если оно так, нужно запретить мне это на уровне компиляции.
Кстати, в свете этой статьи, становиться совсем не очевидным совет использовать operator <, потому что нужно знать специфику этих структур, чтобы определиться "обычное" это сравнение или "специфическое". Вполне возможно что лучше было собсвенный компоратор написать.
Здравствуйте, Максим2006, Вы писали:
М>не понятно, почему не имеет право на существование другая точка зрения, когда рвётся связь по умолчанию между operator < и std::less?
Пусть мы решили, что можно рвать связь между std::less и operator<. Тогда мы должны быть готовы к тому, что std::plus и operator+ будут обозначать разные вещи. И что ++x, x+=1 и x=x+1 будут давать разные результаты. И что объект будет иметь разное состояние в зависимости от того, инициализирован ли он конструктором копирования, или инициализирован по умолчанию, а потом ему присвоено новое значение. Это легально, но аморально и небезопасно. В частности, в последнем случае объекты этого класса вообще не примут в контейнеры стандартной библиотеки.
М>Почему я могу использовать одни объекты библиотеки, но не могу использовать другие? Если оно так, нужно запретить мне это на уровне компиляции.
Да, я считаю, что в этом месте стандартная библиотека предоставляет лишнюю точку расширения. Причём запрет мог бы выражаться не ошибкой компиляции, а простым утверждением в стандарте, типа «специализации plus, minus, multiplies, divides, modulus, negate, equal_to, not_equal_to, greater, less, greater_equal, less_equal, logical_and, logical_or и logical_not обязаны соответствовать по семантике операторам +, -, *, /, %, -, ==, !=, >, <, >=, <=, &&, || и ! соответственно», после чего любая попытка сделать не так есть неопределённое поведение без необходимости диагностики.
С другой стороны, не это ли там и написано?
17.4.3.1/1: […]A program may add template specializations for any standard library template to namespace std. Such a specialization (complete or partial) of a standard library template results in undefined behavior unless the declaration depends on a user-defined name of external linkage and unless the specialization meets the standard library requirements for the original template.
Здравствуйте, Centaur, Вы писали:
C>Здравствуйте, Максим2006, Вы писали:
М>>не понятно, почему не имеет право на существование другая точка зрения, когда рвётся связь по умолчанию между operator < и std::less?
C>Пусть мы решили, что можно рвать связь между std::less и operator<. Тогда мы должны быть готовы к тому, что std::plus и operator+ будут обозначать разные вещи.
Хорошо, готовы.
C>И что ++x, x+=1 и x=x+1 будут давать разные результаты.
Не, не готовы. Это всё через операторы отрабатывает, при чём тут функторы из std?
C>И что объект будет иметь разное состояние в зависимости от того, инициализирован ли он конструктором копирования, или инициализирован по C>умолчанию, а потом ему присвоено новое значение.
Почему такое может быть из-за разрыва связи std::less и operator< ?
C>Это легально, но аморально и небезопасно. В частности, в последнем случае объекты этого класса вообще не примут в контейнеры стандартной библиотеки.
М>>Почему я могу использовать одни объекты библиотеки, но не могу использовать другие? Если оно так, нужно запретить мне это на уровне компиляции.
C>Да, я считаю, что в этом месте стандартная библиотека предоставляет лишнюю точку расширения. Причём запрет мог бы выражаться не ошибкой компиляции, а простым утверждением в стандарте, типа «специализации plus, minus, multiplies, divides, modulus, negate, equal_to, not_equal_to, greater, less, greater_equal, less_equal, logical_and, logical_or и logical_not обязаны соответствовать по семантике операторам +, -, *, /, %, -, ==, !=, >, <, >=, <=, &&, || и ! соответственно», после чего любая попытка сделать не так есть неопределённое поведение без необходимости диагностики. C>С другой стороны, не это ли там и написано? C>
17.4.3.1/1: […]A program may add template specializations for any standard library template to namespace std. Such a specialization (complete or partial) of a standard library template results in undefined behavior unless the declaration depends on a user-defined name of external linkage and unless the specialization meets the standard library requirements for the original template.
По-моему, не это. Тут написано, что будет неопределённое поведение, кроме случаев, когда в обявлении используется пользовательское имя с external linkage и когда специализация соответствует требованиям std для исходного темплейта. А у нас как раз эти случаи.
C>