Re[10]: ненависть к итераторам
От: Videoman Россия https://hts.tv/
Дата: 28.12.20 19:12
Оценка:
Здравствуйте, so5team, Вы писали:

Вы мне предлагали фантазировать на тему constexpr, а сами не хотите фантазировать, тем более что ваш код не компилируется уже по причине того что нельзя char * p = "123456789";. Честно, я уже потерял нить того, что вы мне доказываете. Спор ради спора? У меня и так есть чем занять свое время.
Re[5]: ненависть к итераторам
От: B0FEE664  
Дата: 28.12.20 19:16
Оценка:
Здравствуйте, Videoman, Вы писали:

V>То-есть вы допускаете в STL существование своих функции вычисления значений и отказываете STL в возможности написания своих функций обхода?

Я не сказу за всю современную библиотеку С++20 с std::ranges, но в целом — да. Однако, обычно набора функций std:: хватает для решения задач.

V>На практике у меня функция собственно и инкапсулирует алгоритм прохода по итераторам, он не тривиальный и такого в STL быть не может.


Это смотря что понимать под "не тривиальный". Если у вас цикл или набор циклов по последовательности, то скорее всего можно обойтись функциями из std::
А вот если у вас такой алгоритм, где необходимы обратные смещения по последовательности и число обратных смещений не фиксировано, то тогда на может быть нет смысла использовать STL
И каждый день — без права на ошибку...
Re[11]: ненависть к итераторам
От: so5team https://stiffstream.com
Дата: 28.12.20 19:48
Оценка:
Здравствуйте, Videoman, Вы писали:

V>Вы мне предлагали фантазировать на тему constexpr, а сами не хотите фантазировать


Мне не нужно фантазировать, это вы показали, к какому коду в итоге пришли:
template<typename It, std::enable_if_t<is_const_iterator_of_v<It, char>, int> = 0>
    constexpr It CalcSomething(It str, It last) noexcept;
    template<typename It, std::enable_if_t<is_const_iterator_of_v<It, char16_t>
        || (is_const_iterator_of_v<It, wchar_t> && sizeof(wchar_t) == sizeof(char16_t)), int> = 0>
    constexpr It CalcSomething(It str, It last) noexcept;
    template<typename It, std::enable_if_t<is_const_iterator_of_v<It, char32_t>
        || (is_const_iterator_of_v<It, wchar_t> && sizeof(wchar_t) == sizeof(char32_t)), int> = 0>
    constexpr It CalcSomething(It str, It last) noexcept;

Здесь один тип итератора. И если в итоге вы сделали вариант с двумя типами итераторов, значит мой пример был приведен не зря.

V>При этом ранее вы заостряли внимание на том, что тем более что ваш код не компилируется уже по причине того что нельзя char * p = "123456789";.


Это не ошибка, а предупреждение. Для иллюстрационного примера вполне простительно.
Re: ненависть к итераторам
От: vopl Россия  
Дата: 28.12.20 19:50
Оценка:
Здравствуйте, Videoman, Вы писали:

V>- преобразовать тип итераторов — я не могу


#include <type_traits>
#include <utility>
#include <numeric>
#include <boost/iterator_adaptors.hpp>

/////////0/////////1/////////2/////////3/////////4/////////5/////////6/////////7
template <class SrcIter, class DstValue>
class IterAdaptor
  : public boost::iterator_adaptor<
        IterAdaptor<SrcIter, DstValue>      // Derived
      , SrcIter                             // Base
      , DstValue                            // Value
    >
{
 public:
    explicit IterAdaptor(const IterAdaptor::iterator_adaptor_::base_type& p)
      : IterAdaptor::iterator_adaptor_(p) {}

    DstValue& dereference() const
    {
        DstValue *ptr = reinterpret_cast<DstValue *>(&*this->base_reference());
        return *ptr;
    }
};

/////////0/////////1/////////2/////////3/////////4/////////5/////////6/////////7
template<typename It, typename Value>
struct const_iterator_of_type
{
    static constexpr bool value = std::is_same_v<std::decay_t<decltype(*std::declval<It>())>, Value>;
};

template<typename It, typename Value>
constexpr bool const_iterator_of_type_v = const_iterator_of_type<It, Value>::value;

/////////0/////////1/////////2/////////3/////////4/////////5/////////6/////////7
template<typename It, std::enable_if_t<const_iterator_of_type_v<It, char>, int> = 0>
int CalcSomething(It beg, It end)
{
    return 100 + std::accumulate(beg, end, int{});
}

template<typename It, std::enable_if_t<const_iterator_of_type_v<It, char16_t>, int> = 0>
int CalcSomething(It beg, It end)
{
    return 200 + std::accumulate(beg, end, int{});
}

template<typename It, std::enable_if_t<const_iterator_of_type_v<It, char32_t>, int> = 0>
int CalcSomething(It beg, It end)
{
    return 300 + std::accumulate(beg, end, int{});
}

template<typename It, std::enable_if_t<const_iterator_of_type_v<It, wchar_t>, int> = 0>
int CalcSomething(It beg, It end)
{
    if constexpr (sizeof(wchar_t) == sizeof(char16_t))
    {
        using Adaptor = IterAdaptor<It, const char16_t>;
        return CalcSomething(Adaptor{beg}, Adaptor{end}); // ????
    }
    else if constexpr (sizeof(wchar_t) == sizeof(char32_t))
    {
        using Adaptor = IterAdaptor<It, const char32_t>;
        return CalcSomething(Adaptor{beg}, Adaptor{end}); // ????
    }
    else
        static_assert(!std::is_same_v<wchar_t, char16_t> && !std::is_same_v<wchar_t, char32_t>, "Unsuported wchar_t size!");
}

int main()
{
    wchar_t wchars[7];

    return CalcSomething(std::begin(wchars), std::end(wchars));
}
Re[12]: ненависть к итераторам
От: Videoman Россия https://hts.tv/
Дата: 28.12.20 20:26
Оценка:
Здравствуйте, so5team, Вы писали:

S>Здесь один тип итератора. И если в итоге вы сделали вариант с двумя типами итераторов, значит мой пример был приведен не зря.


У меня в коде именно что один тип итератора . Ваш вариант не скомпилируется, просто у меня нет таких экзотических случаев нигде в коде. Если будет необходимо, я могу разделить типы, это ни на что не повлияет. Еще раз, я-то как раз не оправдываю сложность и объем кода которые в итоге получились, но еще раз, посмотрите повнимательнее на название темы. Весь мой вопрос заключался в одном: неужели для того что бы сделать полностью эквивалентный изначальному код на итераторах нужно так извращаться? Ответ: да!
Re[13]: ненависть к итераторам
От: rg45 СССР  
Дата: 28.12.20 20:43
Оценка: +2
Здравствуйте, Videoman, Вы писали:

V>Весь мой вопрос заключался в одном: неужели для того что бы сделать полностью эквивалентный изначальному код на итераторах нужно так извращаться? Ответ: да!


При этом не стоит упускать из виду, что наиболее удачный рефаторинг — это не обязательно полностью эквивалентный код
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[13]: ненависть к итераторам
От: so5team https://stiffstream.com
Дата: 29.12.20 06:24
Оценка:
Здравствуйте, Videoman, Вы писали:

S>>Здесь один тип итератора. И если в итоге вы сделали вариант с двумя типами итераторов, значит мой пример был приведен не зря.


V>У меня в коде именно что один тип итератора . Ваш вариант не скомпилируется, просто у меня нет таких экзотических случаев нигде в коде.


В C++ном range-for изначально тоже предполагалось, что у begin/end будет одинаковый тип. Но затем в C++17 пришлось вносить изменения.

V>Если будет необходимо, я могу разделить типы, это ни на что не повлияет.


Разве что на объем и сложность кода, т.к. вам придется вписывать дополнительные проверки.

V>Весь мой вопрос заключался в одном: неужели для того что бы сделать полностью эквивалентный изначальному код на итераторах нужно так извращаться? Ответ: да!


Есть замечательное изречение: "Вы дали ему то, что он просил. А я дал ему то, что ему было нужно". Вы явно ждали лишь того, о чем просили.

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

Дело в том, что я так же разрабатываю библиотеки, которые затем разные люди используют в разных условиях и для разных задач. Но исходя из своего опыта я не смог понять под какие сценарии вы затачиваете свой условный calc_something. В частности, от меня ускользают сценарии, в которых пользователь вашей библиотеки будет иметь возможность делать собственные перегрузки ваших функций и почему это может помешать шаблонным функциям в ваших пространствах имен. Отсюда и вопросы. Жаль, что тема использования ADL не получила своего развития. Я так и не понял, как взаимосвязаны разные реализации calc_something в разных пространствах имен с ADL.
Re[14]: ненависть к итераторам
От: Videoman Россия https://hts.tv/
Дата: 29.12.20 08:41
Оценка:
Здравствуйте, so5team, Вы писали:

S>В C++ном range-for изначально тоже предполагалось, что у begin/end будет одинаковый тип. Но затем в C++17 пришлось вносить изменения.


Да, про это я в курсе. Все готовятся к range-ам. Будем решать проблемы по мере их поступления. Пока мы плотно сидим старом С++17. На самом деле не известно насколько все это будет удобно и сколько кода придется писать и как быстро все это будет работать, когда народ массово кинется на 20 стандарт. Посмотрим.

S>Если у вас появилось впечатление, что я пытаюсь в этом разговоре как-то унизить вас или продемонстрировать какое-то превосходство, то уверяю, это не так.


S>Дело в том, что я так же разрабатываю библиотеки, которые затем разные люди используют в разных условиях и для разных задач. Но исходя из своего опыта я не смог понять под какие сценарии вы затачиваете свой условный calc_something. В частности, от меня ускользают сценарии, в которых пользователь вашей библиотеки будет иметь возможность делать собственные перегрузки ваших функций и почему это может помешать шаблонным функциям в ваших пространствах имен. Отсюда и вопросы. Жаль, что тема использования ADL не получила своего развития. Я так и не понял, как взаимосвязаны разные реализации calc_something в разных пространствах имен с ADL.


На самом деле я действительно получил исчерпывающее объяснение на изначальный вопрос и дальнейшее обсуждение выльется в то, что мне просто придется выкладывать кучу кода из библиотеки. Дальше мы начнем обсуждать дальнейшие нюансы и т.д. и т.п. С++ можно обсуждать бесконечно, но к сожалению сейчас просто нет на это времени.
Re[2]: ненависть к итераторам
От: vopl Россия  
Дата: 29.12.20 09:54
Оценка:
Здравствуйте, vopl, Вы писали:

V>Здравствуйте, Videoman, Вы писали:


V>>- преобразовать тип итераторов — я не могу


для компайл тайм это тоже работает, https://gcc.godbolt.org/z/8nnWfE
Re[3]: ненависть к итераторам
От: Videoman Россия https://hts.tv/
Дата: 29.12.20 21:04
Оценка:
Здравствуйте, vopl, Вы писали:

V>Здравствуйте, vopl, Вы писали:


V>>Здравствуйте, Videoman, Вы писали:


V>>>- преобразовать тип итераторов — я не могу


V>для компайл тайм это тоже работает, https://gcc.godbolt.org/z/8nnWfE


Идею я понял, но для меня это слишком креативно . И к сожалению на С++17 не работает, reinterpret_cast там никак.
Re[4]: ненависть к итераторам
От: vopl Россия  
Дата: 30.12.20 07:03
Оценка: 4 (1)
Здравствуйте, Videoman, Вы писали:

V> к сожалению на С++17 не работает

работает
https://gcc.godbolt.org/z/d8so4n

V> reinterpret_cast там никак.

это мелочи, я его туда вкорячил потому что было лень думать. Вместо него можно другие средства запользовать. Например, можно вообще ссылку не предоставлять из operator*, а сразу значение (если тебя это устроит, мне со стороны не видно) — тогда не нужно будет спускаться на уровень указателей, следовательно, никаких ХХХ_cast для указателей вообще. Это лишь пример, не более.
Re[5]: ненависть к итераторам
От: Videoman Россия https://hts.tv/
Дата: 30.12.20 09:12
Оценка:
Здравствуйте, vopl, Вы писали:

V>это мелочи, я его туда вкорячил потому что было лень думать. Вместо него можно другие средства запользовать. Например, можно вообще ссылку не предоставлять из operator*, а сразу значение (если тебя это устроит, мне со стороны не видно) — тогда не нужно будет спускаться на уровень указателей, следовательно, никаких ХХХ_cast для указателей вообще. Это лишь пример, не более.


Идея с адаптером супер. Буду иметь в виду если прижмет где-то. В продакшене я боюсь такое использовать пока
Re[2]: ненависть к итераторам
От: _NN_ www.nemerleweb.com
Дата: 30.12.20 10:41
Оценка:
Здравствуйте, vopl, Вы писали:

Небольшое улучшение с учётом C++20.
Кстати а нужен ли здесь boost вообще ?

#include <type_traits>
#include <utility>
#include <numeric>

/////////0/////////1/////////2/////////3/////////4/////////5/////////6/////////7
template <class SrcIter, class DstValue>
class IterAdaptor
{
public:
    using iterator_category = typename std::iterator_traits<SrcIter>::iterator_category;
    using iterator_concept = typename std::iterator_traits<SrcIter>::iterator_concept;
    using value_type = DstValue;
    using difference_type = std::iter_difference_t<SrcIter>;
    using pointer = std::add_pointer_t<DstValue>;
    using reference = std::add_lvalue_reference_t<DstValue>;

    SrcIter iter;

    constexpr IterAdaptor(SrcIter iter):iter(iter){}

    auto operator<=>(IterAdaptor const& other) const = default;

    constexpr DstValue operator*() { return *iter; }// со ссылками не заморачиваюсь пока, но судя по всему это нужно будет сделать
    constexpr IterAdaptor& operator++() { ++iter; return *this; }
};
/////////0/////////1/////////2/////////3/////////4/////////5/////////6/////////7

template<typename It, typename Value>
concept const_iterable_of_type = std::same_as<std::decay_t<decltype(*std::declval<It>())>, Value>;

using wchar_t_as_char_t =
    std::conditional_t<sizeof(wchar_t) == sizeof(char16_t), char16_t,
    std::conditional_t < sizeof(wchar_t) == sizeof(char32_t), char32_t, void>>;
static_assert(!std::is_same_v<wchar_t_as_char_t, void>);

/////////0/////////1/////////2/////////3/////////4/////////5/////////6/////////7
template<const_iterable_of_type<char> It>
constexpr int CalcSomething(It beg, It end)
{
    return 100 + std::accumulate(beg, end, int{});
}

template<const_iterable_of_type<char16_t> It>
constexpr int CalcSomething(It beg, It end)
{
return 200 + std::accumulate(beg, end, int{});
}

template<const_iterable_of_type<char32_t> It>
constexpr int CalcSomething(It beg, It end)
{
    return 300 + std::accumulate(beg, end, int{});
}

template<const_iterable_of_type<wchar_t> It>
constexpr int CalcSomething(It beg, It end)
{
    using Adaptor = IterAdaptor<It, const wchar_t_as_char_t>;
    return CalcSomething(Adaptor{ beg }, Adaptor{ end }); // ????
}

int main()
{
    constexpr wchar_t wchars[7] = L"abc";

    constexpr auto x = CalcSomething(std::begin(wchars), std::end(wchars));
    return x;
}
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[3]: ненависть к итераторам
От: Videoman Россия https://hts.tv/
Дата: 30.12.20 12:09
Оценка:
Здравствуйте, _NN_, Вы писали:

А вот интересный у меня вопрос, так как я с концептами в живую еще не сталкивался: вот это вот:
template<const_iterable_of_type<wchar_t> It>
constexpr int CalcSomething(It beg, It end)

Будет разрешаться когда оба итератора строго одного типа или, в отличие от варианта на С++, будет позволять любые типы подходящие под concept ? Сдается мне что будет выведен какой-то один тип и придется также дублировать:
template<const_iterable_of_type<wchar_t> ItBegin, const_iterable_of_type<wchar_t> ItEnd>

Что говорят концепты? Это можно будет на них как-то упростить?
Re[4]: ненависть к итераторам
От: watchmaker  
Дата: 30.12.20 13:41
Оценка:
Здравствуйте, Videoman, Вы писали:


V>А вот интересный у меня вопрос, так как я с концептами в живую еще не сталкивался: вот это вот:

V>
V>template<const_iterable_of_type<wchar_t> It>
V>constexpr int CalcSomething(It beg, It end)
V>

V>Будет разрешаться когда оба итератора строго одного типа или, в отличие от варианта на С++, будет позволять любые типы подходящие под concept ?
В смысле, чтобы работал следующий вызов?
CalcSomething(std::list<wchar_t>::const_iterator{}, std::vector<wchar_t>::const_iterator{});
Тогда если в теле функции CalcSomething будет написано It a;, то какой тип из двух должна получить эта переменная a?


V>Сдается мне что будет выведен какой-то один тип

Да. Конструкция
template<Concept T> 
auto foo(T param) …
эквивалентна
template<typename T>
requires Concept<T>
auto foo(T param) …

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

V>Что говорят концепты? Это можно будет на них как-то упростить?

Если тебе не нужно что-то дополнительное от типа, то можно просто не использовать полную запись: выкинуть template и использовать concept auto для аргументов. Работает так же как и в остальных местах: каждый auto выводится независимо.
Re[5]: ненависть к итераторам
От: _NN_ www.nemerleweb.com
Дата: 30.12.20 13:59
Оценка:
Здравствуйте, watchmaker, Вы писали:


V>>Сдается мне что будет выведен какой-то один тип

W>Да. Конструкция
template<Concept T> 
W>auto foo(T param) …
W>
эквивалентна
template<typename T>
W>requires Concept<T>
W>auto foo(T param) …
W>

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

Кстати, хорошо упомянуть, что в случае более одного аргумента компилятор ставить тип в начало, что может удивить

template<const_iterable_of_type<char> It>
constexpr int CalcSomething(It beg, It end);

==
template<typename It> requires const_iterable_of_type<It, char>
constexpr int CalcSomething(It beg, It end);
http://rsdn.nemerleweb.com
http://nemerleweb.com
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.