Непонятки с set
От: tors Украина http://dotjob.110mb.com/resume/
Дата: 19.04.06 12:22
Оценка:
struct TInfoEx
{
TInfo Info;
String Name;
};

set<TInfoEx> InfoEx;

TInfoEx inf;
.
.
.
InfoEx.insert(inf);

operator< not implemented in type TInfoEx for arguments of the same type

вероятно нужно реализовать operator< для этой структуры и вложенных в нее структур?
как это сделать — пример плиз
Re: Непонятки с set
От: DigitalGuru Россия http://svetlyak.ru
Дата: 19.04.06 12:29
Оценка:
Здравствуйте, tors, Вы писали:

T>вероятно нужно реализовать operator< для этой структуры и вложенных в нее структур?

T>как это сделать — пример плиз

Вы совершенно правы, мой дарогой Ватсон. Вы определенно делаете успехи!

Ну как то так:

bool operator <( const TInfoEx& left, const TInfoEx& right )
{
  return что-то
}
Re: Непонятки с set
От: Bell Россия  
Дата: 19.04.06 12:29
Оценка:
Здравствуйте, 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
{
    // тут нужно решить что является ключом в TInfoEx
    return std::less<TInfo>()(_X.Info, _Y.Info);
}
Re[2]: Непонятки с set
От: DigitalGuru Россия http://svetlyak.ru
Дата: 19.04.06 14:11
Оценка:
Здравствуйте, Аноним, Вы писали:

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 <, это в общем-то никого волновать не должно
Re[4]: Непонятки с set
От: Centaur Россия  
Дата: 19.04.06 16:22
Оценка: 1 (1) +1
Здравствуйте, Аноним, Вы писали:

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 < — это вынужденная мера, хотя и очень желательная.
Re[6]: Непонятки с set
От: Centaur Россия  
Дата: 20.04.06 09:36
Оценка:
Здравствуйте, Аноним, Вы писали:

А>operator < нужно определить сразу же за определением std::less<>, если размер проекта предполагает, что разные пользователи этой структуры могут его опредилить. Оператор, конечно же, вызывает std::less.


Дефолтный std::less уже реализован в терминах operator<. Зачем ставить всё с ног на голову?
Re[7]: Непонятки с set
От: Максим2006 Беларусь  
Дата: 20.04.06 10:02
Оценка: -1
Здравствуйте, Centaur, Вы писали:

C>Здравствуйте, Аноним, Вы писали:


А>>operator < нужно определить сразу же за определением std::less<>, если размер проекта предполагает, что разные пользователи этой структуры могут его опредилить. Оператор, конечно же, вызывает std::less.


Я — это Аноним

C>Дефолтный std::less уже реализован в терминах operator<. Зачем ставить всё с ног на голову?

Это ещё знать нужно, когда разбираешься с кодом. Определение только operator < усложняет код. А следующий абзац предыдущего поста — не аргумент?

К тому же, что будет если кто-нибудь потом определит std::less также как operator < (о чём сетовали тут: http://www.rsdn.ru/Forum/Message.aspx?mid=1856924&amp;only=1)?
Re[8]: Непонятки с set
От: Centaur Россия  
Дата: 20.04.06 14:52
Оценка:
Здравствуйте, Максим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&amp;only=1)?


Если у нас есть operator<, то вряд ли кому-то придёт в голову специализировать std::less, потому что любой код, использующий std::less, скомпилируется и будет использовать стандартную реализацию. Если же у нас будет специализация std::less, то кто-нибудь попробует написать код с использованием operator<, обломается и может пойти реализовывать его. И с большой вероятностью сделает не так, как в нашей специализации std::less. И тем более не будет реализовывать operator< через std::less, потому что знает, что по умолчанию делается наоборот.

Собственно говоря, всё это можно найти у Scott’а Meyers’а в Effetive STL, Item 42.
Re[9]: Непонятки с set
От: Максим2006 Беларусь  
Дата: 21.04.06 17:04
Оценка: +1
Здравствуйте, 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&amp;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 <, потому что нужно знать специфику этих структур, чтобы определиться "обычное" это сравнение или "специфическое". Вполне возможно что лучше было собсвенный компоратор написать.
Re[10]: Непонятки с set
От: Centaur Россия  
Дата: 22.04.06 06:22
Оценка:
Здравствуйте, Максим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.


template <class T> struct less : binary_function<T,T,bool> {
  bool operator()(const T& x, const T& y) const;
};
20.3.3/5: operator() returns x < y.

Не следует ли трактовать 20.3.3/5 как standard library requirements для шаблона less? Для сравнения, требования на std::swap выглядят так:

template<class T> void swap(T& a, T& b);
25.2.2/1: Requires: Type T is CopyConstructible (20.1.3) and Assignable (23.1).
25.2.2/2: Effects: Exchanges values stored in two locations.

— без привязки к конкретным операциям.
Re[11]: std::less<T> и operator <
От: Максим2006 Беларусь  
Дата: 25.04.06 07:33
Оценка:
Здравствуйте, 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>

template <class T> struct less : binary_function<T,T,bool> {
    bool operator()(const T& x, const T& y) const;
};
20.3.3/5: operator() returns x < y.

C>Не следует ли трактовать 20.3.3/5 как standard library requirements для шаблона less?
По-моему, не следует, ведь этот пункт находится под заголовком

The library provides basic function object classes for all of the comparison operators in the language (5.9, 5.10)

и provide — это предусматривать, предоставлять, но не require (требовать)

C>Для сравнения, требования на std::swap выглядят так:

template<class T> void swap(T& a, T& b);
25.2.2/1: Requires: Type T is CopyConstructible (20.1.3) and Assignable (23.1).
25.2.2/2: Effects: Exchanges values stored in two locations.

C>— без привязки к конкретным операциям.
так тут и написано:

[...]Requires[...]

это и есть реальное требование (причём на тип, а не на функтор)
Re[12]: std::less<T> и operator <
От: оwl  
Дата: 25.04.06 10:31
Оценка:
Господа, а можно ли специализировать указатель на класс?
Т.е.
set<TInfoEx *> InfoEx; 
bool std::less< TInfoEx *>::operator()(const TInfoEx * _X, const TInfoEx *  _Y) const
{
  return что-то
}

На такой код компилятор ругается.
Re[13]: std::less<T> и operator <
От: оwl  
Дата: 25.04.06 11:12
Оценка:
Здравствуйте, оwl, Вы писали:

оwl>Господа, а можно ли специализировать указатель на класс?

оwl>Т.е.
оwl>
оwl>set<TInfoEx *> InfoEx; 
оwl>bool std::less< TInfoEx *>::operator()(const TInfoEx * _X, const TInfoEx *  _Y) const
оwl>{
оwl>  return что-то
оwl>}
оwl>

оwl>На такой код компилятор ругается.
Sorry за беспокойство.
Разобрался, лечится использованием typedef
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.