Мы работаем с внутренней библиотекой, которая имеет класс StringBuilder
, который используется для преобразования списка VariableValue
объектов в строку.VariableValue
объекты могут быть построены из произвольных типов (специализируя шаблонную функцию convertVariable
).Вот код, который описывает сценарий:
struct VariableValue {
// Construct a 'VariableValue' object, a variant type which can represent values of
// one of four types: string, number (integer), boolean and floating point.
explicit VariableValue( const std::string &serializedData );
// Getters, typesafe; will yield an exception when calling the wrong getter.
const std::string &asString() const;
bool asBoolean() const;
// ..
// Convert any VariableValue object into a string
static std::string convertToString( const VariableValue &v );
};
// Template to be specialized so that user types can be casted into a
// VariableValue object
template <typename T>
VariableValue convertVariable( T v );
// Helper class to 'concatenate' multiple VariableValue objects into a single string.
class StringBuilder {
public:
const std::string &result() const;
template <class T>
StringBuilder &operator<<( T v ) {
return *this << convertVariable( v );
}
private:
std::ostringstream m_stream;
};
template <>
inline StringBuilder &StringBuilder::operator<<( const VariableValue &v ) {
m_stream << VariableValue::convertToString( v );
return *this;
}
Это все очень хорошо.Клиенты просто должны были предоставить соответствующую специализацию для шаблона convertVariable
(наша библиотека уже предоставляет множество специализаций для различных типов), и тогда можно использовать StringBuilder.Почти.
Проблема в том, что он не работает с типами, которые нельзя копировать.Все шаблонные функции принимают свои аргументы по значению.А в случае шаблона convertVariable
изменить подпись довольно дорого (поскольку существует довольно много специализаций).Поэтому, хотя я могу заставить шаблон StringBuilder::operator<<
принимать const T &
, это не сильно поможет, так как экземпляр convertVariable
будет просто вызываться с T
(так как часть ссылки на констант удаляется, покавывод типов шаблонов).Если я исправлю это, указав тип явно, как в:
class StringBuilder {
public:
// ...
template <class T>
StringBuilder &operator<<( const T &v ) {
return *this << convertVariable<const T &>( v );
}
};
Компоновщик будет жаловаться, потому что он больше не находит старые специализации (например, template <> VariableValue convertVariable( int )
), так как он ищет специализации, которые принимают ссылку-to-const.
Кто-нибудь знает, как я могу настроить класс StringBuilder
, чтобы я мог передавать не копируемые объекты (т. е. объекты, тип которых не допускает ни конструирования, ни копирования) в operator<<
функция?