Здравствуйте, B0FEE664, Вы писали:
BFE>Является ли следующий код валидным? И если нет, то почему?
Мне кажется, что такой код — прямой прыжок в область implementation-defined или undefined behavior.
Тут даже не понятно, что вы имеете ввиду под "валидный": что он соберется? что значение it будет изменено в коде find_if? что значение it не будет изменено в коде find_if?
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
Здравствуйте, B0FEE664, Вы писали:
BFE>Является ли следующий код валидным?
Не является, если под валидностью подразумевается, что код скомпилируется и что после вызова find_if возвращённое значение совпадёт со значением it.
Здравствуйте, VTT, Вы писали:
BFE>>Является ли следующий код валидным? И если нет, то почему? VTT>Мне кажется, что такой код — прямой прыжок в область implementation-defined или undefined behavior.
Почему?
VTT>Тут даже не понятно, что вы имеете ввиду под "валидный": что он соберется? что значение it будет изменено в коде find_if? что значение it не будет изменено в коде find_if?
Меня интересует результат и соответствие стандарту. Вот по стандарту он должен работать или нет?
Здравствуйте, watchmaker, Вы писали:
BFE>>Является ли следующий код валидным? W>Не является, если под валидностью подразумевается, что код скомпилируется и что после вызова find_if возвращённое значение совпадёт со значением it.
Код не должен компилироваться? Почему? И почему значение может не совпадать?
Здравствуйте, B0FEE664, Вы писали:
BFE>Здравствуйте, watchmaker, Вы писали:
BFE>>>Является ли следующий код валидным? W>>Не является, если под валидностью подразумевается, что код скомпилируется и что после вызова find_if возвращённое значение совпадёт со значением it.
BFE>И почему значение может не совпадать?
Нет, давай лучше ты сначала расскажешь, почему считаешь, что оно должно совпадать :)
Я вот не вижу в стандарте ни единого основания для такой уверенности. Это, разумеется, если смотреть как описан алгоритм find_if в стандарте, а не в художественном изложении на всяких сайтах в интернете вроде cplusplus.com. На последнем, например, написано, что поведение функции эквивалентно некой представленной реализации, хотя на самом деле такого требования нет и на практике реализация как раз отличается. Причём часть отличий как раз затрагивает процесс копирования итераторов. Хотя для равенства it и возвращаемого занчения важна детерминистичность этого процесса.
Чего-то я не понимаю. Т.е. сначала Вы ищете итератор, указывающий на "элемент больше либо равный двух", затем, если нашлось, забываете про этот итератор и модифицируете первый элемент массива? Или Вы хотите модифицировать найденный элемент?
Стандарт вроде бы говорит что
25.2.5.1
Returns: The first iterator i in the range [first,last) for which the following corresponding conditions hold: *i == value, pred(*i) != false, pred(*i) == false. Returns last if no such iterator is found.
Так что код на первый взгляд выглядит нормальным. Странным, но нормальным.
Здравствуйте, watchmaker, Вы писали:
W>>>Не является, если под валидностью подразумевается, что код скомпилируется и что после вызова find_if возвращённое значение совпадёт со значением it. BFE>>И почему значение может не совпадать? W>Нет, давай лучше ты сначала расскажешь, почему считаешь, что оно должно совпадать
find_if в качестве возвращаемого значения имеет то же тип, что и итератор, поэтому, если передаётся ссылка, то должна быть возвращена легальная ссылка на найденный объект. Насколько я понимаю, не существует способа вернуть валидную ссылку на локальный объект. Значит ссылка на найденный аргумент и на первый параметер должны совпадать. .
MD>Чего-то я не понимаю. Т.е. сначала Вы ищете итератор, указывающий на "элемент больше либо равный двух", затем, если нашлось, забываете про этот итератор и модифицируете первый элемент массива?
Почему первый? Я же ссылку передал. Её же ожидаю в качестве результата. А какую ещё валидную ссылку может вернуть find_if?
Я ожидаю, что it будет указывать на найденный элемент.
Здравствуйте, B0FEE664, Вы писали:
VTT>>Мне кажется, что такой код — прямой прыжок в область implementation-defined или undefined behavior. BFE>Почему?
BFE>Меня интересует результат и соответствие стандарту. Вот по стандарту он должен работать или нет?
В стандарте определяется только значение итератора, возвращаемого из функции, что именно делается с аргументами там не описывается.
В стандарте говорится, что первые два аргумента должны соответствовать требованиям для InputIterator, т.е. среди прочего быть CopyConstructible, CopyAssignable, и Destructible. Вообще говоря, я не уверен что InputIterator & соответствует этим требованиям.
Так или иначе, функция принимающая эти итераторы, может их копировать и присваивать (и предикат тоже!), как хочет (разрешение на копирование предиката там даже специально отмечено). Так что соответствующая стандарту реализация вполне может делать так:
...
find_if(InputIterator first, InputIterator last, Predicate pred)
{
auto iter = first;
while(iter != last)
{
if(pred(*iter))
{
break;
}
++iter;
}
return(iter);
}
или даже так:
...
find_if(InputIterator first, InputIterator last, Predicate pred)
{
auto iter = first;
while(iter != last)
{
if(pred(*iter))
{
break;
}
++iter;
}
first = last;
return(iter);
}
Говорить дальше не было нужды. Как и все космонавты, капитан Нортон не испытывал особого доверия к явлениям, внешне слишком заманчивым.
Здравствуйте, B0FEE664, Вы писали:
BFE>Значит ссылка на найденный аргумент и на первый параметер должны совпадать. .
А, например, со вторым аргументом ей что мешает совпадать?
Рассмотри все варианты. А то почему-то делаешь выбор в пользу какого-то одного, игнорируя остальные.
BFE>Насколько я понимаю, не существует способа вернуть валидную ссылку на локальный объект.
Тут скорее другой принцип: Garbage in, garbage out.
Здравствуйте, VTT, Вы писали:
VTT>В стандарте определяется только значение итератора, возвращаемого из функции, что именно делается с аргументами там не описывается.
Ну, тип то его явно указан.
VTT>В стандарте говорится, что первые два аргумента должны соответствовать требованиям для InputIterator, т.е. среди прочего быть CopyConstructible, CopyAssignable, и Destructible. Вообще говоря, я не уверен что InputIterator & соответствует этим требованиям.
VTT>Так или иначе, функция принимающая эти итераторы, может их копировать и присваивать (и предикат тоже!), как хочет (разрешение на копирование предиката там даже специально отмечено). Так что соответствующая стандарту реализация вполне может делать так: VTT>
VTT>...
VTT>find_if(InputIterator first, InputIterator last, Predicate pred)
VTT>{
VTT> auto iter = first;
VTT>...
VTT> return(iter);
VTT>}
VTT>
VTT>или даже так: VTT>
VTT>...
VTT>find_if(InputIterator first, InputIterator last, Predicate pred)
VTT>{
VTT> auto iter = first;
VTT>...
VTT> return(iter);
VTT>}
VTT>
Я бы сказал, что это ошибка — возвращение висячей ссылки.
Здравствуйте, watchmaker, Вы писали:
BFE>>Значит ссылка на найденный аргумент и на первый параметер должны совпадать. . W>А, например, со вторым аргументом ей что мешает совпадать? W>Рассмотри все варианты. А то почему-то делаешь выбор в пользу какого-то одного, игнорируя остальные.
Чтож. Это аргумент.
BFE>>Насколько я понимаю, не существует способа вернуть валидную ссылку на локальный объект. W>Тут скорее другой принцип: Garbage in, garbage out.
Ну нет. Данные валидные. Более того, заставляют платить за то, что не используется: за копирование итераторов.
Невалиден. Как минимум потому что нет специализации iterator_traits. find_if может иметь разные реализации для разных категорий iterator_traits<I>::iterator_category
Может не скомпилироваться, если find_if внутри использует указатель на итератор. Или ссылку на итератор, если используешь старый С++, где reference collapsing не работает.
Здравствуйте, B0FEE664, Вы писали:
BFE>Почему первый? Я же ссылку передал. Её же ожидаю в качестве результата. А какую ещё валидную ссылку может вернуть find_if? BFE>Я ожидаю, что it будет указывать на найденный элемент.
Хорошо, давайте снова процитирую Стандарт, но более полно (если быт точным, то это draft n3290, но тут давно ничего не меняется):
25.2.5 Find [alg.find]
template<class InputIterator, class T> InputIterator find(InputIterator first, InputIterator last, const T& value);
template<class InputIterator, class Predicate> InputIterator find_if(InputIterator first, InputIterator last, Predicate pred);
template<class InputIterator, class Predicate> InputIterator find_if_not(InputIterator first, InputIterator last, Predicate pred);
1 Returns: The first iterator i in the range [first,last) for which the following corresponding conditions hold: *i == value, pred(*i) != false, pred(*i) == false. Returns last if no such iterator is found.
2 Complexity: At most last — first applications of the corresponding predicate.
Здесь ничего не говорится про взаимосвязь входных параметров и внутреннего tmp, бегущего по диапазону [first, last). Итого, Вы можете предполагать иммутабельность входных параметров, но никак не можете ожидать мутабельность — это ни из чего не следует. И даже если какая-то реализация даёт такой эффект, он именно side effect, implementation-defined.
Что касается ссылки, то у меня ощущение, что она сыграет лишь как "передача it по ссылке, а не copy construction". Ведь Вы сравниваете результат find_if() с итератором itEnd, а не указателем на него — и всё компилируется? Ну и опять же, что ссылка, что не ссылка — это будет соптимизировано любым уважающим себя компилятором, так что не ожидаю разницы в итоговом коде, если честно.
На толкователя стандарта не претендую, но reference to object-это non-type template-parameter, а прототип find_if определён
с type template-parameter, поэтому строка std::find_if<std::vector<int>::iterator&, decltype(oFn)>(it, itEnd, oFn) есть
нарушение, так как содержит type-referеnce в параметрах шаблона. И вообще не понятно зачем такие качели, если копирование
итераторов по ссылке не есть дорогостоящая операция, можно смело делать it=std::find_if(itBeg, itEnd, oFn)
MD>template<class InputIterator, class Predicate> InputIterator find_if(InputIterator first, InputIterator last, Predicate pred);
MD>Здесь ничего не говорится про взаимосвязь входных параметров и внутреннего tmp, бегущего по диапазону [first, last). Итого, Вы можете предполагать иммутабельность входных параметров, но никак не можете ожидать мутабельность — это ни из чего не следует. И даже если какая-то реализация даёт такой эффект, он именно side effect, implementation-defined.
то я считаю, что вправе рассчитывать на корректную работу этой функции с ссылками если обратное не оговорено в документации.
Т.е. вызов:
int n = 32;
ink k = fun<int&>(n);
должен отработать корректно. Корректно — это значит не иметь Undefined Behavior.
Согласны?
MD>Что касается ссылки, то у меня ощущение, что она сыграет лишь как "передача it по ссылке, а не copy construction". Ведь Вы сравниваете результат find_if() с итератором itEnd, а не указателем на него — и всё компилируется?
Компилируется или нет — зависит от реализации std::find_if
MD>Ну и опять же, что ссылка, что не ссылка — это будет соптимизировано любым уважающим себя компилятором, так что не ожидаю разницы в итоговом коде, если честно.
Разница в том, куда будет указывать переданный аргумент.
, но могу дополнить. Если я вижу функцию, типа: BFE>
BFE>template<class T> T fun(T t);
BFE>
BFE>то я считаю, что вправе рассчитывать на корректную работу этой функции с ссылками если обратное не оговорено в документации. BFE>Т.е. вызов: BFE>
BFE> int n = 32;
BFE> ink k = fun<int&>(n);
BFE>
BFE>должен отработать корректно. Корректно — это значит не иметь Undefined Behavior. BFE>Согласны?
Согласен, безусловно. Более того, k и n имеют один и тот же тип. Но почему Вы ожидаете, что k и n должны быть взаимосвязаны по своему значению, если в специализации шаблона фигурирует символ ссылки на тип? Вот краеугольный камень, вокруг которого мы бродим уже второй день.
Копировать по ссылке, клонировать, делать swap или ещё что — это внутренняя кухня имплементации. Не закладывайтесь на неё.