std::back_insert_iterator::value_type
От: пффф  
Дата: 23.07.23 07:52
Оценка:
Привет

cppreference говорит, что это всегда void, но у std::iterator value_type вполне себе задан как тип value_type контейнера, или чего он там итерирует.

Проблема в таком коде:
template<OutputIterator>
void doSomething(OutputIterator out)
{
    while(...)
    {
        *out++ = ...; //!!!
    }
}


Тут ругается на несоответствие типа. В конкретном случае у меня out это char итератор, а справа std::uint8_t.
Я хотел скастить через OutputIterator::value_type, но у back_insert_iterator это void.

И что теперь делать?
Re: std::back_insert_iterator::value_type
От: sergii.p  
Дата: 23.07.23 09:25
Оценка:
Здравствуйте, пффф, Вы писали:

П>И что теперь делать?


надо минимальный пример. У меня работает https://godbolt.org/z/Y549n7Ta4
Как *iter++, так и *++iter
Re[2]: std::back_insert_iterator::value_type
От: пффф  
Дата: 23.07.23 09:39
Оценка:
Здравствуйте, sergii.p, Вы писали:

П>>И что теперь делать?


SP>надо минимальный пример. У меня работает https://godbolt.org/z/Y549n7Ta4

SP>Как *iter++, так и *++iter

Сорян, не указал, у меня MSVC.

Попробовал перенастроить твой пример под MSVC, но что-то не срослось — https://godbolt.org/z/vh1v7oh3Y
Причем какая-то проблема с cmake

UPD Запилил твой пример заново, получил такую же, как у меня, ошибку — https://gcc.godbolt.org/z/r95Khhxn6
Отредактировано 23.07.2023 10:01 пффф . Предыдущая версия .
Re[3]: std::back_insert_iterator::value_type
От: sergii.p  
Дата: 23.07.23 10:11
Оценка:
Здравствуйте, пффф, Вы писали:

П>UPD Запилил твой пример заново, получил такую же, как у меня, ошибку — https://gcc.godbolt.org/z/r95Khhxn6


ошибку конвертации можно убрать исправив лямбду

[n=std::uint8_t{0}]() mutable { return static_cast<char>(++n); })


наверное это более правильно, потому как библиотечный код не должен делать неявные преобразования.
Re[4]: std::back_insert_iterator::value_type
От: пффф  
Дата: 23.07.23 10:15
Оценка:
Здравствуйте, sergii.p, Вы писали:

SP>ошибку конвертации можно убрать исправив лямбду


SP>
SP>[n=std::uint8_t{0}]() mutable { return static_cast<char>(++n); })
SP>


SP>наверное это более правильно, потому как библиотечный код не должен делать неявные преобразования.


Можно, но у меня нет лямбды, есть функция, которая получает два итератора на байты, и OutputIterator. Этот OutputIterator я создаю для std::string, но ничто не должно мне помешать сделать тоже самое для вектора из uint8_t. Поэтому я хотел скастить к OutputIterator::value_type, но у back_insert_iterator это всегда void. Сейчас ковыряюсь через iterator_traits, но там тоже какое-то г полезло

UPD Переделал пример, как это у меня с шаблоном, и как я пытаюсь с кастом к value_type — https://gcc.godbolt.org/z/5n89nv6jY
Отредактировано 23.07.2023 10:31 пффф . Предыдущая версия .
Re[5]: std::back_insert_iterator::value_type
От: so5team https://stiffstream.com
Дата: 23.07.23 10:36
Оценка:
Здравствуйте, пффф, Вы писали:

П>Можно, но у меня нет лямбды, есть функция, которая получает два итератора на байты, и OutputIterator. Этот OutputIterator я создаю для std::string, но ничто не должно мне помешать сделать тоже самое для вектора из uint8_t. Поэтому я хотел скастить к OutputIterator::value_type, но у back_insert_iterator это всегда void. Сейчас ковыряюсь через iterator_traits, но там тоже какое-то г полезло


П>UPD Переделал пример, как это у меня с шаблоном, и как я пытаюсь с кастом к value_type — https://gcc.godbolt.org/z/5n89nv6jY


Мало что понял из вашего описания, но вроде бы вам нужно что-то типа: https://gcc.godbolt.org/z/35PfPj7hh
Re[6]: std::back_insert_iterator::value_type
От: пффф  
Дата: 23.07.23 10:41
Оценка:
Здравствуйте, so5team, Вы писали:

S>Мало что понял из вашего описания, но вроде бы вам нужно что-то типа: https://gcc.godbolt.org/z/35PfPj7hh


Похоже, что да. Я только не понял, а почему с iterator_traits не работает? back_insert_iterator — не настоящий итератор, и для него нет специализации iterator_traits?

Я полагал, что для него есть всё то, что ты написал
Re[5]: std::back_insert_iterator::value_type
От: Sm0ke Россия ksi
Дата: 23.07.23 21:25
Оценка:
Здравствуйте, пффф, Вы писали:

П>Можно, но у меня нет лямбды, есть функция, которая получает два итератора на байты, и OutputIterator. Этот OutputIterator я создаю для std::string, но ничто не должно мне помешать сделать тоже самое для вектора из uint8_t. Поэтому я хотел скастить к OutputIterator::value_type, но у back_insert_iterator это всегда void. Сейчас ковыряюсь через iterator_traits, но там тоже какое-то г полезло


П>UPD Переделал пример, как это у меня с шаблоном, и как я пытаюсь с кастом к value_type — https://gcc.godbolt.org/z/5n89nv6jY


Получить value_type можно через container_type итератора.

using IterType = OutputIterator;
using IterCharType = typename IterType :: container_type :: value_type;
for(size_t i = 0; i < num; ++i, ++iter)
{
  *iter = static_cast<IterCharType>( func() );
}


Вот так должно работать. https://gcc.godbolt.org/z/Knfa41Tbc
Отредактировано 23.07.2023 21:25 Sm0ke . Предыдущая версия .
Re[6]: std::back_insert_iterator::value_type
От: пффф  
Дата: 24.07.23 07:16
Оценка:
Здравствуйте, Sm0ke, Вы писали:

S>Получить value_type можно через container_type итератора.


S>
S>using IterType = OutputIterator;
S>using IterCharType = typename IterType :: container_type :: value_type;
S>for(size_t i = 0; i < num; ++i, ++iter)
S>{
S>  *iter = static_cast<IterCharType>( func() );
S>}
S>


S>Вот так должно работать. https://gcc.godbolt.org/z/Knfa41Tbc


Спасибо, но хотелось универсальный способ найти
Re: std::back_insert_iterator::value_type
От: rg45 СССР  
Дата: 24.07.23 22:14
Оценка:
Здравствуйте, пффф, Вы писали:

П>Проблема в таком коде:

П>
П>template<OutputIterator>
П>void doSomething(OutputIterator out)
П>{
П>    while(...)
П>    {
П>        *out++ = ...; //!!!
П>    }
П>}
П>


П>Тут ругается на несоответствие типа. В конкретном случае у меня out это char итератор, а справа std::uint8_t.

П>Я хотел скастить через OutputIterator::value_type, но у back_insert_iterator это void.

П>И что теперь делать?


Можно как-то так попробовать:

template<OutputIterator>
void doSomething(OutputIterator out)
{
    using value_type = std::decay_t(decltype(*out));

    while(...)
    {
        *out++ = value_type(rhs); //!!!
    }
}
--
Не можешь достичь желаемого — пожелай достигнутого.
Re[2]: std::back_insert_iterator::value_type
От: Sm0ke Россия ksi
Дата: 25.07.23 10:18
Оценка: 10 (1)
Здравствуйте, rg45, Вы писали:

R>Можно как-то так попробовать:


R>
R>template<OutputIterator>
R>void doSomething(OutputIterator out)
R>{
R>    using value_type = std::decay_t(decltype(*out));

R>    while(...)
R>    {
R>        *out++ = value_type(rhs); //!!!
R>    }
R>}
R>


Вы это пробовали?
back_insert_iterator : оператор * возвращает *this
у него Перегружен оператор =
Это работать не будет.
Re[7]: std::back_insert_iterator::value_type
От: Sm0ke Россия ksi
Дата: 25.07.23 10:46
Оценка: 2 (1)
Здравствуйте, пффф, Вы писали:

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


S>>Получить value_type можно через container_type итератора.


S>>
S>>using IterType = OutputIterator;
S>>using IterCharType = typename IterType :: container_type :: value_type;
S>>for(size_t i = 0; i < num; ++i, ++iter)
S>>{
S>>  *iter = static_cast<IterCharType>( func() );
S>>}
S>>


S>>Вот так должно работать. https://gcc.godbolt.org/z/Knfa41Tbc


П>Спасибо, но хотелось универсальный способ найти


Заглянув в описание std::void_t<> https://en.cppreference.com/w/cpp/types/void_t
я нашёл универсальное решение (аналог SFINAE) для случаев когда у итератора есть вложенный container_type, и когда его нет.

#include <iostream>
#include <iterator>
#include <algorithm>
#include <vector>
#include <cstdint>
#include <type_traits>

template<typename T, typename = void>
struct iterator_trait : public std::iterator_traits<T> {};
 
template<typename T>
struct iterator_trait<
    T, std::void_t<typename T::container_type>
> : public std::iterator_traits<
    typename T::container_type::iterator
> {};

template<typename OutputIterator>
void gen_n(OutputIterator iter, size_t num, auto&& func)
{
    using IterType = OutputIterator;
    using IterCharType = iterator_trait<IterType>::value_type;
    
    for(size_t i = 0; i < num; ++i, ++iter)
    {
        *iter = static_cast<IterCharType>( func() );
    }
}

int main() {
  std::vector<char> v;
  /*std::generate_n(
    std::back_insert_iterator(v),
    std::uint8_t{10}, [n=std::uint8_t{0}]() mutable { return ++n; }
  );*/
  gen_n(std::back_insert_iterator{v}, 10
    , [n=std::uint8_t{0}]() mutable { return ++n; });
 
  for (int n : v) {
    std::cout << n << ' ';
  }
  std::cout << '\n';
  return 0;
}


тест: https://gcc.godbolt.org/z/r7qz3bKox
Re[3]: std::back_insert_iterator::value_type
От: rg45 СССР  
Дата: 25.07.23 17:58
Оценка:
Здравствуйте, Sm0ke, Вы писали:

S>Вы это пробовали?

S>back_insert_iterator : оператор * возвращает *this
S>у него Перегружен оператор =
S>Это работать не будет.

Ясно. Нет, не пробовал. Как-то выпустил я из поля зрения такую возможность.
--
Не можешь достичь желаемого — пожелай достигнутого.
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.