Форум программистов, компьютерный форум CyberForum.ru

Объяснить код - C++

Восстановить пароль Регистрация
 
Demispace
0 / 0 / 0
Регистрация: 28.09.2014
Сообщений: 5
01.10.2015, 22:22     Объяснить код #1
Может кто-нибудь смог бы закомментировать данные участок кода или объяснить что за что отвечает( можно еще и ссылки на сторонние ресуры скинуть)..? Пока дальше циклов и простых функций не продвинулся, а разобраться с кодом очень надо! Заранее спасибо.
... конкретно данный участок позволяет найти повторяющиеся слова(2 и более раза) в строке и образует из них новую последовательность.

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
template <class ContainerT>
void Tokenize(const std::string& str,
    ContainerT& tokens,
    const std::string& delimiters = " ",
    bool trimEmpty = false)
{
    std::string::size_type pos, lastPos = 0;
 
    using value_type = typename ContainerT::value_type;
    using size_type = typename ContainerT::size_type;
 
    while (true)
    {
        pos = str.find_first_of(delimiters, lastPos);
        if (pos == std::string::npos)
        {
            pos = str.length();
 
            if (pos != lastPos || !trimEmpty)
                tokens.push_back(value_type(str.data() + lastPos,
                    (size_type)pos - lastPos));
            break;
        }
        else
        {
            if (pos != lastPos || !trimEmpty)
                tokens.push_back(value_type(str.data() + lastPos,
                    (size_type)pos - lastPos));
        }
 
        lastPos = pos + 1;
    }
}
 
void Cut(string& text, const string& word)
{
    const auto it = search(text.begin(), text.end(), word.begin(), word.end());
    text.erase(it, it + word.size());
}
Лучшие ответы (1)
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
01.10.2015, 22:22     Объяснить код
Посмотрите здесь:

Объяснить код (рекурсивная функция). C++
C++ Структура (объяснить код программы)
Объяснить код на С++ C++
Прошу объяснить код С++ C++
Объяснить код C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
S_el
1906 / 1501 / 295
Регистрация: 15.12.2013
Сообщений: 5,911
01.10.2015, 22:23     Объяснить код #2
Demispace, почему не спросите там,где нашли код?
Задавайте конкретные вопросы + прокомментируйте код так как понимаете.
Demispace
0 / 0 / 0
Регистрация: 28.09.2014
Сообщений: 5
01.10.2015, 22:25  [ТС]     Объяснить код #3
Туда где я нашёл этот код он тоже попал случайно)
Хорошо, попробую описать сам для начала.
S_el
1906 / 1501 / 295
Регистрация: 15.12.2013
Сообщений: 5,911
01.10.2015, 22:33     Объяснить код #4
Цитата Сообщение от Demispace Посмотреть сообщение
Там где я нашёл его тоже где-то нашли)
Плохо ищете:
http://stackoverflow.com/questions/2...-a-string-in-c
и вот:
Определить, какое слово встречается в строке чаще всего

Цитата Сообщение от Demispace Посмотреть сообщение
попробую описать сам для начала.
С этого и надо было начинать.
Operok
125 / 123 / 33
Регистрация: 15.02.2015
Сообщений: 386
Завершенные тесты: 2
01.10.2015, 22:43     Объяснить код #5
Demispace, функция реализует метод split (разбиение строки на подстроки), результат помещается в контейнер (шаблонный тип)
hoggy
5030 / 2113 / 403
Регистрация: 15.11.2014
Сообщений: 4,797
Завершенные тесты: 1
01.10.2015, 22:43     Объяснить код #6
судя по буковкам код был взят у меня)


обратите внимание:

C++
1
2
    using value_type = typename ContainerT::value_type;
    using size_type = typename ContainerT::size_type;
нигде не используется.
но исправлять было лень

Удалить из текста все слова, которые входят в него один раз
Operok
125 / 123 / 33
Регистрация: 15.02.2015
Сообщений: 386
Завершенные тесты: 2
01.10.2015, 23:38     Объяснить код #7
а не лучше ли объявить функцию так:
C++
1
2
3
4
5
6
template <template <typename, typename> typename StrContainerT>
void Tokenize(const std::string& str,
    StrContainerT<std::string, std::allocator<std::string>>& tokens,
    const std::string& delimiters = " ",
    bool trimEmpty = false)
{...}
если не указать явный value_type для контейнера, то при передаче функции контейнера для несоответствующего типа, искать концы сложновато будет. Проблема в размере объявления такой функции (из-за аллокатора).
Demispace
0 / 0 / 0
Регистрация: 28.09.2014
Сообщений: 5
01.10.2015, 23:41  [ТС]     Объяснить код #8
Скорее всего не совсем правильная трактовка кода... но все же!
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
template <class ContainerT>// шаблон функции с пользовательским типом данных
void Tokenize(const std::string& str, //Ну вот здесь начинается сама функцию, в неё передаем...
    ContainerT& tokens, //
    const std::string& delimiters = " ", // ограничители в виде пробела(?)
    bool trimEmpty = false) //булеву переменную с начальным значением "ложь"
{
    std::string::size_type pos, lastPos = 0; //что связанное с размером строки... pos и lastPos - непонятно вообще для чего.
 
    using value_type = typename ContainerT::value_type; //?? получение доступа к типам? контейнера
    using size_type = typename ContainerT::size_type; // тоже самое только к другим
 
    while (true)// начало цикла
    {
        pos = str.find_first_of(delimiters, lastPos); //поиск первого символа указанного в аргументах(т.е. delimiterts, а он у нас равен пробелу??) причем last_Pos указывает на..??? не понимаю
        if (pos == std::string::npos) если позиция до или после равна npos(не понимаю), то
        {
            pos = str.length();// в pos загоняем длину строки
 
            if (pos != lastPos || !trimEmpty) //если pos не равна lastPos или Булева ложна, то:
                tokens.push_back(value_type(str.data() + lastPos, // добавляет в конце строки какой-то тип?? который мы нашли и что то еще(
                    (size_type)pos - lastPos)); //и еще ..??
            break;
        }
        else //иначе...
        {
            if (pos != lastPos || !trimEmpty) если pos не равен lastPos или ложна TrimEmpty
                tokens.push_back(value_type(str.data() + lastPos, // опять что-то добавляем в конец
                    (size_type)pos - lastPos)); //...
        }
 
        lastPos = pos + 1; //увеличиваем на единицу 
    }
}
 
void Cut(string& text, const string& word)
{
    const auto it = search(text.begin(), text.end(), word.begin(), word.end()); // в пределах от начала(text.begin) и до text.end ищет последовательность word.begin()-word.end()
    text.erase(it, it + word.size()); ///....
}
Operok
125 / 123 / 33
Регистрация: 15.02.2015
Сообщений: 386
Завершенные тесты: 2
02.10.2015, 00:05     Объяснить код #9
Сообщение было отмечено автором темы, экспертом или модератором как ответ
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
template <class ContainerT>// контейнер STL (не ассоциативный), должен быть для типа std::string
void Tokenize(const std::string& str, //строка, которую делим
    ContainerT& tokens, //контейнер в который складываем результат
    const std::string& delimiters = " ", // подстрока, которая будет делить строку
    bool trimEmpty = false) // флаг - складываем в контейнер пустые строки (когда два разделителя подряд идут)
{
    std::string::size_type pos, lastPos = 0; //индексы элементов строки
 
    using value_type = typename ContainerT::value_type; // это тип данных хранимых в контейнере (в нашем случае это псевдоним std::string)
    using size_type = typename ContainerT::size_type; // тип используемый контейнером для индексации и задания размера (скорее всего псевдоним size_t)
 
    while (true)// начало цикла (тут не прогадаешь)
    {
        pos = str.find_first_of(delimiters, lastPos); // получения позиции первого вхождения "разделителя" в строке
        if (pos == std::string::npos) если позиция не найдена, то
        {
            pos = str.length();// в pos загоняем длину строки (так как мы проверили всю строку, то pos должен быть на один больше позиции последнего символа, т.е. str.length())
 
            if (pos != lastPos || !trimEmpty) //если есть что копировать или можно добавлять в контейнер пустые строки
                tokens.push_back(value_type(str.data() + lastPos, 
                    (size_type)pos - lastPos));  // добавляем в контейнер подстроку (с позиции lastPos, кол-во - разница pos и lastPos)
            break; //это был конец строки, закругляемся
        }
        else //иначе... 
        {
            //тут тоже самое, но только без break
            if (pos != lastPos || !trimEmpty)
                tokens.push_back(value_type(str.data() + lastPos,
                    (size_type)pos - lastPos));
        }
      
        lastPos = pos + 1; //устанавливаем значение lastPos равным позиции следующим после последнего встреченного разделителя
    }
}
 
void Cut(string& text, const string& word)
{
    const auto it = search(text.begin(), text.end(), word.begin(), word.end()); // ищем в строке text подстроку word
    text.erase(it, it + word.size()); // удаляем подстроку word, смещая оставшуюся часть строки text
}

Не по теме:

вот же делать то мне нечего

hoggy
5030 / 2113 / 403
Регистрация: 15.11.2014
Сообщений: 4,797
Завершенные тесты: 1
02.10.2015, 01:00     Объяснить код #10
Цитата Сообщение от Operok Посмотреть сообщение
а не лучше ли объявить функцию так:
не лучше.

в промышленной версии фигурирует один единственные параметр - тип контейнера.
все остальные типы выводятся из него.

что позволяет запихивать, как вектора, так и листы,
как char`овые стринги, так и wchar_t`вые.


что касаетя возможных ошибок компиляции - компилятор сообщит вам прямым английским текстом.
в трех соснах не заблудитесь.
Operok
125 / 123 / 33
Регистрация: 15.02.2015
Сообщений: 386
Завершенные тесты: 2
02.10.2015, 10:31     Объяснить код #11
Цитата Сообщение от hoggy Посмотреть сообщение
в промышленной версии фигурирует один единственные параметр - тип контейнера.
все остальные типы выводятся из него.
Уверенность в том, что на практике будет использоваться "правильные типы" не может не радовать. Но мне не нравится, когда на конечного пользователя "библиотеки" возлагают подобный выбор. Да он не сможет запихать туда левый тип, но ругаться на подобное уже будет компилятор, а синтаксический анализатор. Однако, если в "мою версию" передать объект некоторого шаблонно класса (не STL контейнера) "<typename T, typename Al = std::allocator<T>>", то ругаться тоже будет компилятор на несуществующие метода/поля шаблонного типа. Поэтому соглашусь, не очень-то он и лучше, но зато сразу видны ограничения для передаваемого параметра "нужен контейнер (если давать понятные имена шаблонным типам) для типа std::string".
Цитата Сообщение от hoggy Посмотреть сообщение
что позволяет запихивать, как вектора, так и листы,
как char`овые стринги, так и wchar_t`вые.
все эти контейнеры подходят под шаблонный тип "<template <typename = std::string, typename = std::allicator<std::string>> class ContainerT>". А вот контейнер для wstring передать туда опять не получится, конструктор "value_type(str.data() + lastPos, (size_type)pos - lastPos)", где str - это std::string, не поддерживается. Тут наверное нужно добавить шаблонный параметр <typename CharT> и передавать std::basic_string<CharT> как делимую строку, так и разделитель.

В общем, как мне кажется, это уже обсуждение стилей метапрограммирования. "шаблонные шаблонные параметры" сильнее ограничивают выбор типа в пользу STL контейнера, но очень громоздкие (этой проблеме посвящается), указание обобщенного шаблонного типа выглядит более лаконично и просто, но требуют некоторых комментарий и пояснений по её использованию.

Не по теме:

Цитата Сообщение от hoggy Посмотреть сообщение
компилятор сообщит вам прямым английским текстом.
поставил студию 2015... русифицированную... теперь компилятор сообщает мне всё прямым русским текстом

MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
02.10.2015, 19:41     Объяснить код
Еще ссылки по теме:

C++ Объяснить код рекурсии
C++ ООП. Подробно объяснить код
Объяснить код C++

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
hoggy
5030 / 2113 / 403
Регистрация: 15.11.2014
Сообщений: 4,797
Завершенные тесты: 1
02.10.2015, 19:41     Объяснить код #12
Цитата Сообщение от Operok Посмотреть сообщение
но ругаться на подобное уже будет компилятор, а синтаксический анализатор.
как то не понятно сформулированно.

если что, то все проверки типизации происходят времени компиляции.
так что компилятор в данном случае сам отрабатает,
как статический анализатор.

вот простейший пример:
C++
1
2
3
4
5
6
7
template <class ContainerT>      
void Tokenize(
    const std::string& str,
    ContainerT& tokens,
    const std::string& delimiters = " ",
    bool trimEmpty = false
)
Проблема данного кода заключается в том,
что аргумент const std::string& str не имеет связи с типом контейнера.

допустим, нам нужен юникод.
у нас контейнер:
std::vector<std::wstring>

и соотвественно, парсить мы хотим const std::wstring&
в качестве источника данных

однако шаблон это не учитывает.
в нем жестко прибито гвоздями
const std::string&

все, только если править код руками.

а между тем, любой stl-compatible контейнер имеет паблик-тайпдефы,
чере которые можно было бы вытащить информацию о типе элементов контейнера:

C++
1
2
3
4
5
6
7
8
template <class ContainerT>      
void Tokenize(
    const typename ContainerT::value_type& str,
    ContainerT& tokens,
    const typename ContainerT::value_type& delimiters 
        = Default<typename ContainerT::value_type>(),
    bool trimEmpty = false
)
и все, и никаких проблем.

идем дальше:

если мы запихиваем в какой нибудь std::vector, или std::list
то очевидно, что токены нужно закидывать в конец.
но если это std::set какой нибудь, значит порядок закидывания токенов нам не важен.

проблема в том, что у std::set нету методов аля emplace_back

для std::map ещё сложнее - здесь не понятно, что есть ключ, и что значение.
однако это так же легко разруливается в компалтайме за счет стратегии.

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

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

смысл идеи в том, что бы один раз написать шаблон,
и больше его не трогать.

он должен отвечать наиболее частым случаям использования,
и позволять модифицировать поведение без необходимости
копашиться в его потрохах и что-то там править.

Добавлено через 5 минут
Цитата Сообщение от Operok Посмотреть сообщение
все эти контейнеры подходят под шаблонный тип "<template <typename = std::string, typename = std::allicator<std::string>> class ContainerT>".
зачем усложнять?
обычное T и все прекрасно работает.
Yandex
Объявления
02.10.2015, 19:41     Объяснить код
Ответ Создать тему
Опции темы

Текущее время: 00:17. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru