LINUX.ORG.RU

Доступ к lambda capture

 


0

1

Вообщем, есть какой-то такой код:

int main() {
	Cell<int> a = 5;
	Cell<float> b = 2.3;
	
	Cell<double> c = { { &a, &b }, [=, &a, &b] { return a + b; } };

	return 0;
}

Проблема в том, что дублируется одна и та же чушь два раза (&a, &b). Ну это ладно, хуже то, что компилятор молчит если забыть добавить в список переменную, но оставить ее в лямбде. Вопрос в том, как вытащить из лямбды переменные которые она захватила, это возможно?

★★★
Ответ на: комментарий от nanoolinux

Я только не понял зачем тебе такой код и что он делает если честно.

Cell<T> это обертка над одной переменной типа T.

c зависит от a и b. Значение c кешуруется, то есть a и b нужно знать какие Cell-ы захватила лямбда, что бы сообщать c о том, что их изменили.

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

Там много и не интересно.

template <typename Type>
class _CellDepend : _CellBind {
	friend class Cell<Type>;
public:
	using InitListT = initializer_list<_CellBind*>;
	
/* ... */

private:
	_CellDepend(InitListT initList, const function<Type()> reaction)
			: reaction(reaction) {
		for(_CellBind* i : initList) {
			i->bind(this);
		}
	}
/* ... */
};

/* ... */

template <typename Type>
class Cell {
private:
	enum class Tag { Depend, Value };
	Tag tag;
	
	union Uni {
	public:
		_CellDepend<Type> depend;
		_CellValue<Type> value;

		Uni(const Type& value)
			: value(value) {}

		Uni(typename _CellDepend<Type>::InitListT initList, const function<Type()> reaction) 
			: depend(initList, reaction) {}
		
		Uni() {} 
		~Uni() {} 
	} uni;
	
public:
	Cell(const Type& value)
		: tag(Tag::Value), uni(value) {}
	
	Cell(typename _CellDepend<Type>::InitListT initList, const function<Type()> reaction)
		: tag(Tag::Depend), uni(initList, reaction) {}
	
/* ... */
};


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

разве [=, &a, &b] не означает - захватить все, кроме &a и &b?

Нет, это значит захватывать все по значению, кроме a и b, их по ссылке.

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

Дык все и так работает. Просто мне не нравится что нужно 2 раза перечислять одно и тоже. Это с учетом того что лямбда в что-то такое раскрывается.

class __ABC123 {
private
   Cell<int>& a;
   Cell<float>& b;

public:
  int operator () {
    return a + b;
  }
}

Щас пытался на Си препроцессоре накостылять, не осилил, забил короче.

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

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

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

Думал так сделать. Но будет только хуже.

Лишний раз нужно писать типы в аргументах, компилятор сверить их не сможет, так как тип списка initializer_list<_CellBind*>. Соответственно и в аргументы лямбды попадет _CellBind - предок _CellValue<T> (нужен reinterpret_cast<Cell<int>>(a) + reinterpret_cast<Cell<float>>(b) вместо a + b, кароче никакой типизации), плюс к этому, аргументов должно быть произвольное количество.

Можно заменить список на variadic template, тогда и с типизацией все будет нормально, но придется делать лямбду первым аргументом, что совершенно не читабельно и ошибиться будет проще: два одинаковых списка нужно поддерживать на расстоянии в несколько строк и с разными отступами.

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

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

dimon555 ★★★★★
()

Вопрос в том, как вытащить из лямбды переменные которые она захватила, это возможно?

Скорее всего, вам это и не нужно. Можно зависимости между cell'ами считать в рантайме (а именно, если эвальюатор для c вызвал a и b, то c зависит от a и b; а если в зависимости от какого-то условия c не вызвал a, то c от a не зависит) - это дажее точнее выйдет. Для этого можно держать глобальную thread-local-переменную, в которой запоминать текущуий вычисляемый cell, и при вызове другого cell'а записывать вызванный cell в зависимости к вычисляемому cell'у.

dmitry_vk ★★★
()
Последнее исправление: dmitry_vk (всего исправлений: 1)
Ответ на: комментарий от dmitry_vk

а именно, если эвальюатор для c вызвал a и b, то c зависит от a и b; а если в зависимости от какого-то условия c не вызвал a, то c от a не зависит

Это разрешают простые лямбды (если захватить a и b по ссылке). Мне нужно что бы при изменении a и b, сообщалось c, о том что она изменилась (changed = true лямбда не вычисляется, она вычисляется только если нужно значение c). То есть a и b должны узнавать что от них зависит c до вычисления c.

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