Есть несколько вариантов, которые я могу придумать, каждый со своим уродством.
Один очевидный вариант - использовать указатели (вероятно, unique_ptr
) вместо ссылок.Конечно, чтобы это работало, требуется либо выделение из кучи, либо пользовательские распределители.Я думаю, что с хорошим распределителем у этого подхода есть некоторые достоинства.С другой стороны, перегрузка оператора будет просто неприятной.
Другой подход - хранить подвыражения по значению, а не по константной ссылке.Эффективность этого подхода очень зависит от компилятора, но, поскольку вы в основном имеете дело с кучей временных файлов, я бы предположил, что современные компиляторы могут оптимизировать копии (или, по крайней мере, много копий).
Последний подход позволяет сохранить ту же структуру в вашем коде, но заставляет пользователя оценивать выражение.Это требует, чтобы у вас был только один итеративный тип, который является базовым типом выражения (скажем, std::vector<int>
).Ни один из классов выражений не должен иметь методы или функции begin
и end
, определенные для них, а должен быть просто конвертируемым в базовый тип.Таким образом, код, подобный for(auto x : expr)
, потерпит неудачу во время компиляции (поскольку expr
не повторяется), но запись for(auto x : static_cast<vector<int>>(expr))
работает, потому что выражение уже вычислено.
Если вы надеялись использовать диапазон-на основе циклов для реализации операций шаблона выражения, вы можете предоставить частные или защищенные begin
и end
методы в ваших классах шаблона выражения.Просто убедитесь, что каждый класс шаблона имеет доступ к begin
и end
методам других шаблонных классов.В этом контексте все должно быть в порядке, поскольку шаблон выражения является параметром функции, поэтому вам не придется беспокоиться о висячих ссылках при написании цикла внутри этой функции.