Ниже много лирики, основная мысль в конце выделена жирным.
CEG>Я пытался перегрузить функцию Hold(), чтобы одна вызывалась для ссылок, а другая — для значений. Не выходит — в обоих случаях перегрузка разрешается в пользу какой-то одной функции, а не разных. Либо перегрузка вообще не разрешается.
Различать значения и ссылки очень, очень мучительно.
(Говорят, в C++0x есть rvalue references, но я в этом скорее осло, чем копенгаген).
Если ты имеешь дело с нульарными функциями, то можешь передавать не значение, а собственно функцию.
Выдрать тип из сигнатуры (T() или T const&()) — труда не составит.
Но это уж как-то совсем ограниченное решение.
CEG>Есть ли какие-то решения? Есть ли решение, пригодное для MSVC6 (ограниченная поддержка шаблонов, в частности, отсутствие частичной специализации)?
Мне кажется, правильно будет
1) Сперва задуматься — чем для тебя (в контексте твоей задачи) различаются ссылки и значения.
Ну, скажем, такое различие: значение, будучи временным объектом, живёт недолго; зато его можно копировать.
А так ли страшно, что значение живёт недолго?
Если сам Hold живёт в пределах полного выражения, то ссылка на временный объект вполне всех устроит.
А так ли страшно, что глобальную ссылку нельзя копировать?
Вообще, — страшно: полиморфизм, всё-таки. Но если функции, возвращающие глобальные ссылки, не апкастят тип, эта проблема снимается.
И ещё раз страшно, если эксплуатируется уникальность адреса либо копирование слишком дорого.
2) Постараться каким-то способом придти к единообразию.
Единообразие в виде константных ссылок — ограничено, в силу проблемы времени жизни. (Кстати, из-за этого я проклял библиотеку Локи).
Единообразие в виде значений — это либо беспощадное копирование, либо использование прокси-объектов.
Наконец, можно достичь единообразия в виде умных указателей (тот же boost::shared_ptr может и с глобальными неубиваемыми объектами иметь дело). Куча плюсов и минус в виде нагрузки на динамическую память.
Прокси могут быть
— настоящими, в иерархии твоих TFubar'ов
— резко отличными по типу: начиная с банальных указателей вместо ссылок, и кончая boost::cref и его аналогами
Выбор техники зависит от того, насколько мучительно будет переделать программу.
Грубо говоря, если const Fubar& foo() заменить на cref<Fubar> foo() или на Fubar* foo() — много ли клиентского кода отвалится?