LINUX.ORG.RU

Есть ли в C++ аналог yield итератора?

 


1

1

В некоторых языках наблюдаю такой тип выборки последовательностей (код условный):

fun getSequence(params): Sequence {
    while (true) {
        value = toDoSomething(params);
        yield value;
    }
}
...
for (auto value: getSequence(something)) {
    ...
}
Т.е. yield возвращает очередное значение последовательности и прерывает выполнение до запроса следующего значения. При запросе следующего значения возобновляет выполнение с прерванной позиции.

Для С++ похожая схема реализуется с передачей лямбды в параметр, выглядит так:

void getSequence(auto params, const auto &task) {
    while (true) {
        auto value = toDoSomething(params);
        task(value);
    }
}
...
getSequence(something, [&](const auto &value) {
   ...
});
Можно ли сделать такой итератор с учетом может каких-либо последний фич от с++2z?

В С++20 есть yield оператор. Точнее, co_yield. Поддержка корутин пока неполная как в clang, так и в gcc, но тривиальные примеры работают.

Siborgium ★★★★★
()

А «схема» реализуется через обычный объект с begin-end, а-ля:

struct Sequence {
    size_t counter_ = 0;
    size_t end_     = 0;

    constexpr auto current() { return counter_; }
    constexpr auto next() { counter_++; }
    constexpr auto eor() { return counter_ == end_; }

    struct End {};
    struct Begin {
        Sequence& ref;
        constexpr auto operator != (End) { return !ref.eor(); }
        decltype(auto) operator * () {
            return ref.current();
        }
        auto& operator ++ () {
            ref.next();
            return *this;
        }
    };

    constexpr auto begin() { return Begin{ *this }; }
    constexpr auto end() { return End{}; }
};

int main() {
    Sequence sequence{0, 10};
    for (auto i: sequence) {
        std::cout << i << '\n';
    }
}

Siborgium ★★★★★
()
Последнее исправление: Siborgium (всего исправлений: 1)

есть корутины в 20м стандарте и есть корутины в бусте. при этом в бусте stackful корутины и фибры есть. http://boost.org/libs/coroutine2

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

В С++20 есть yield оператор. Точнее, co_yield.

Понял, спасибо. Стормозил, не подумал погуглить. Похоже оно работает с распараллеливанием...

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

Поддержка корутин пока неполная как в clang, так и в gcc

gcc говорит что полная с gcc 10.

https://gcc.gnu.org/projects/cxx-status.html#cxx20

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

fsb4000 ★★★★★
()

Вариант для си

// #include <stdio.h>
#define F_CPU 4800000

#include <avr/io.h>
#include <util/delay.h>

typedef uint8_t u8;

#define CONCAT_(x, y) x ## y
#define CONCAT(x, y) CONCAT_(x, y)

#define var static u8
#define yield(expr) lastLine = &&CONCAT(a, __LINE__); return (expr); CONCAT(a, __LINE__):

u8 colorGenerator() {
  static void *lastLine = &&a0; goto *lastLine;
  a0:
  for(var i = 0; i < 8; i += 1) {
    yield(i);
  }
  return -1;
}

int main() {
  for(u8 i = 0; i != -1; i = colorGenerator()) {
    PORTB = i;
    //printf("%i", i);
  }
  return 0;
}

Вариант для крестов

struct ColorGenerator {
	#define var auto
	
	i8 randDir() {
	};
	
	u8 randColorN() {
	};
	u8 randAlgo() {
	};

	i8 dir = 0;
	u8 startN = 0;
	u8 i = 0;
	u8 n = 0;
	u8 temp;
	
	void *lastLine = nullptr; 
	
	ColorAndDelay operator()() {
		#define yield
		#define emitColor(colorArg, delayArg) lastLine = &&CONCAT(a, __LINE__); \
			return ColorAndDelay { .color =  (u8)(colorArg), .delay = (u8)(delayArg) }; \
			CONCAT(a, __LINE__):
		
		if(lastLine == nullptr) lastLine = &&a0; goto *lastLine; a0:

		while(1) {
			switch(randAlgo()) {
				case(0): {
					for(var i = 0; i < rainbowLength; i += 1) {
						yield emitColor(i, 100);
					}
				} break;
				case(1): case(3): case(4): {
					startN = randColorN() + 6;
					yield emitColor(startN, 50);
					yield emitColor(startN + 1, 50);
					yield emitColor(startN, 100);
				} break;
				default: {
					
				}
			}
		}
		return ColorAndDelay();
		
		#undef var 
		#undef yield
		#undef emitColor
	}
};

Вариант для C++ мне нравится больше. И нету оверхеда на гуарды для static

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

Да не, Вы не понимаете. Это настоящий художник. Все нюансы и тонкости совершенства его кода последующие поколения будут еще долго исследовать и обсуждать.

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