LINUX.ORG.RU

Если надо именно реализовать, то смотри исходники yield. В чем проблема то?

AF ★★★
()

Как реализовать подобный функционал?

Можешь просто что-то типа такого сделать:

class MyClass {
public:
    MyClass(T1 arg1, T2 arg2) {
        this->_arg1 = arg1;
        ...
    }

    T* yield() {
        /*считаешь очередной член последовательности
          сейвишь промежуточные значение this->_arg1 и т.п.*/
        if( the_end ) return NULL;
        else return some_value;
    }
};

А вообще аналогом yield, в C++, являются итераторы(см. как это сделано скажем в C++).

Norgat ★★★★★
()
Ответ на: комментарий от deterok

Ты просто будешь дёграть метод yield() и проверять, не вылез ли NULL. Поне не вылез NULL - можно дёргать дальше.

Примерно так:

MyClass a = MyClass(a,b,c);

T* tmp;
while ((tmp = a.yield())!= NULL) {
    //do_work...
}

Если я тебя неправильно понял, то напиши пример кода с yield, который иллюстрирует нужное поведение.

Norgat ★★★★★
()
Ответ на: комментарий от deterok

По нормальному - никак. Можно только передумать логику алгоритма на вариант без yield (через итераторы и т.п.), что в сложных случаях будет выглядеть намного менее наглядно.

snizovtsev ★★★★★
()
Ответ на: комментарий от deterok

Если нужно имитировать типичное применение yield, используй итераторы, как уже сказали. Полноценных сопрограмм/продолжений в С++ нет, есть только всякие костыли например на основе метода Даффа, гугли.

Но, раз уже взялся за С++, лучше немного перестроить мышление и отказаться от этой затеи.

staseg ★★★★★
()
Ответ на: комментарий от deterok

Можно и готовый

#include <sched.h>
class MyThreadWrapper
{
public:
   yield(){
     sched_yield();
   }
}
AF ★★★
()

Сигналы/слоты, например. Или callback.

schizoid ★★★
()

Спасибо всем, итераторы буду дергать.

deterok ★★★★★
() автор топика

Лучше сразу переходить на F#, чем так мучаться. Там лучший yield из тех, что я видел.

dave ★★★★★
()
Ответ на: комментарий от dave

оно уже где-нибудь кроме .net работает?

anonymous
()
Ответ на: комментарий от deterok

он под .net, так что или managed c++, что весьма убого, или FFI. Попробуй хаскелл.

anonymous
()
Ответ на: комментарий от deterok

Зря ты так радуешься. Во первых, эффективные продолжения для традиционных подходов реализации С++ невозможны, так что тормоза обеспечены. Во-вторых, из POSIX.1-2008 контексты выкинули ссылаясь на проблемы с переносимостью и рекомендовали использовать потоки.

Begemoth ★★★★★
()
Ответ на: комментарий от deterok

Помоему не очень распространен еще, лучше буду пользовать C++

Тогда пиши обычные итераторы в стиле стандартной библиотеки.

Begemoth ★★★★★
()
Ответ на: комментарий от Begemoth

Вы меня убедили, буду итераторы пользовать.

deterok ★★★★★
() автор топика

std::function из 2011-го года или, альтернативно, boost::function покрывает возможности yield и идёт дальше.

quiet_readonly ★★★★
()
Ответ на: комментарий от deterok

Да, я пошутил. Но F# действительно очень хороший язык, и по фичам впереди планеты всей. Уже без шуток. А вызывать сишный код в .NET можно через PInvoke.

dave ★★★★★
()
Ответ на: комментарий от KblCb

Представь себе, да! Речь о вычислительных выражениях и sequence/list/array expression. Там есть yield. Когда императивная по сути конструкция преобразуется в композицию функций с вовлечением продолжений. Полнейший гибрид. Чистому хаскелю такое и не снилось! ;)

dave ★★★★★
()
Ответ на: комментарий от Norgat

Мне тоже, сказал 'А', говори 'Б':)

deterok ★★★★★
() автор топика
Ответ на: комментарий от Norgat

Просто возьми какое-нибудь сложное sequence expression с циклами while / for и участками yield / yield!. Потом попробуй представить, как это может преобразовываться компилятором. Если лень, то можно попробовать скормить квазицитатору. Только читать выхлоп квазицитатора не очень удобно, но кое-что понять можно, да хотя бы увидеть, какие там функции появляются.

Другими словами, на вход подаем некую конструкцию, похожую на императивный код. На выходе имеем довольно-таки «функциональный» код в лучших традициях ФП. Одним словом, вычислительные выражения.

Например,

<@ seq { while true do yield 1 } @>
dave ★★★★★
()
Ответ на: комментарий от dave

Э, может я такой глупый(я например не знал до сих пор, что в C++ есть итераторы), но лично мне пример не понятен(слишком сложно описан), можно в более простом варианте?:)

deterok ★★★★★
() автор топика
Ответ на: комментарий от deterok

В более простом варианте?

Yield в F# - это часть так называемых вычислительных выражений (computation expressions), а они являются синтаксическим сахаром, чем-то похожим на нотацию do в хаскеле или for-comprehension в скале, но только лучше (с моей точки зрения).

Например, конструкция

builder {
    while true do
         yield 1
}

будет преобразована в что-то похожее на (сильно не проверял - могу ошибиться)

builder.Delay (fun () ->
     builder.While (fun () -> true,
          builder.Delay (fun () ->
               builder.Yield (1)))))

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

Наконец, yield есть в C#. Там реализован другой подход через конечный автомат, но код тоже преобразуется. Вот этот подход, кстати, могли бы и реализовать в C++.

Подход F# более общий, и мне он очень нравится. Если ты слышал об асинхронных вычислениях async в F#, то они реализуются тем же самым способом, что и yield.

dave ★★★★★
()
Ответ на: комментарий от deterok

Тут основная фишка в том, что yield позволяет генерировать значения, имея внутреннее состояние. Итераторы этого не умеют. Они как бы вывернуты на изнанку.

dave ★★★★★
()
Ответ на: комментарий от red_eyed_peguin

man makecontext, getcontext, swapcontext

И кстати, это не С++, это POSIX. И ещё вопрос, ты конечно, уже проанализировал как эти функции взаимодействуют с конструкторами и деструкторами?

Begemoth ★★★★★
()
Ответ на: комментарий от dave

То есть мы компилируем менее понятный императивный код в менее производительный функциональный?

KblCb ★★★★★
()
Ответ на: комментарий от Begemoth

Олфаги-олдфажники, а гвозди вы микроскопом забиваете?

Переключение контекстов — единственно возможный нормальный yield. И причем тут микроскоп?

red_eyed_peguin
()
Ответ на: комментарий от red_eyed_peguin

Единственно возможный нормальный yield - это преобразование кода при компиляции, посмотри хоть на генераторы в Python.

Begemoth ★★★★★
()
Ответ на: комментарий от KblCb

В данном случае менее понятного императивного кода не существует. Yield - сложная штука.

dave ★★★★★
()
Ответ на: комментарий от Begemoth

посмотри хоть на генераторы в Python

Зачем ты киваешь в сторону языка, являющегося классическим примером убогого проектирования?

Единственно возможный нормальный yield - это преобразование кода при компиляции

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

red_eyed_peguin
()
Ответ на: комментарий от Begemoth

И ещё вопрос, ты конечно, уже проанализировал как эти функции взаимодействуют с конструкторами и деструкторами?

Контексты и деструкторы существуют в параллельных мирах и никак друг на друга не влияют. С чем реально могут быть проблемы, так это с исключениями.

red_eyed_peguin
()
Ответ на: комментарий от red_eyed_peguin

Контексты и деструкторы существуют в параллельных мирах и никак друг на друга не влияют.

  1. Создаём объект на стеке.
  2. Сохраняем контекст.
  3. Выходим из области видимости объекта.
  4. Восстанавливаем контекст.
  5. UB

Для нормального переключения контекста нужен аналог dynamic-wind.

Begemoth ★★★★★
()
Ответ на: комментарий от Begemoth

Ты как-то неправильно понимаешь слово «контекст». Безусловно, можно сделать getcontext а затем переход на него через setcontext/swapcontext, но yield опирается на вызов функции внутри другого контекста, куда входит и отдельный стек. Никаких конфликтов с деструкторами при этом не возникает.

А то что ты написал — это пальба по собственным ногам. В сишечке ведь можно ведь и *(int*)(ptrdiff_t)random() = random() сделать.

red_eyed_peguin
()
Ответ на: комментарий от Begemoth

В случае с yield мы сразу после сохранения контекста возвращаемся из функции. В чистом си тоже никто не мешает сделать malloc, сохранить контекст, сделать free и восстановить контекст.

vzzo ★★★
()
Ответ на: комментарий от Begemoth

Во-вторых, из POSIX.1-2008 контексты выкинули ссылаясь на проблемы с переносимостью и рекомендовали использовать потоки.

Никто не мешает эмулировать контексты через setjmp/longjmp (см. PCL)

kemm
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.