Шаблоны выражений и ранжирование на основе в C++11

Насколько я понимаю, шаблоны выражений будут разбиты на ранжированные в C++11, так как for (auto x : expr) имеет неявное auto&& __range = expr в этом, и это приведет к висящим ссылкам.

Есть ли способ создать классы шаблонов выражений так, чтобы они либо правильно вели себя в зависимости от ранжирования, либо, по крайней мере, вызывали ошибку компиляции?

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

2 ответа

Решение

Я могу придумать несколько вариантов, каждый со своим уродством.

Одним из очевидных вариантов является использование указателей (вероятно, unique_ptr) вместо ссылок. Конечно, чтобы это работало, требуется либо выделение из кучи, либо пользовательские распределители. Я думаю, что с хорошим распределителем у этого подхода есть свои достоинства. С другой стороны, перегрузка оператора будет просто неприятной.

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

Последний подход позволяет сохранить ту же структуру в вашем коде, но заставляет пользователя оценивать выражение. Это требует, чтобы у вас был только один итеративный тип, который является базовым типом выражения (скажем, std::vector<int>). Ни один из классов выражений не должен иметь begin а также end методы или функции, определенные для них, но должны быть просто конвертируемыми в базовый тип. Таким образом, код как for(auto x : expr) потерпит неудачу во время компиляции (так как expr не повторяется), но написание for(auto x : static_cast<vector<int>>(expr)) работает, потому что выражение уже оценено.

Если вы надеялись использовать циклы for на основе диапазона для реализации операций шаблона выражения, то вы можете предоставить закрытый или защищенный begin а также end методы в вашем классе шаблонов выражений. Просто убедитесь, что каждый класс шаблона может получить доступ к begin а также end методы других шаблонных классов. В этом контексте все должно быть в порядке, поскольку шаблон выражения является параметром функции, поэтому вам не придется беспокоиться о висячих ссылках при написании цикла внутри этой функции.

Как правило, с этим ничего не поделаешь. Если вы задаете выражение в качестве диапазона, оно должно разрешаться до того, что будет действительным после инициализации for заявление. И нет никакого способа обнаружить во время компиляции, что какой-либо конкретный тип был выведен auto,

Было бы лучше сделать вашу систему выражений более ориентированной на перемещение, чтобы она не содержала ссылки. Это даст гораздо более безопасные результаты с auto чем пытаться хранить ссылки на потенциально мертвые вещи. Если вас беспокоит копирование для неподвижных типов, просто живите с этим.

Другие вопросы по тегам