我们正在使用一个内部库,其中包含一个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
调用(因为参考在推导模板类型时剥离-to-const部分)。如果我通过明确指定类型来解决此问题,如:
class StringBuilder {
public:
// ...
template <class T>
StringBuilder &operator<<( const T &v ) {
return *this << convertVariable<const T &>( v );
}
};
链接器会抱怨,因为它不再找到旧的特化(例如template <> VariableValue convertVariable( int )
),因为它寻找带有引用到const的特化。
有没有人知道如何调整StringBuilder
类,以便我可以将不可复制的对象(即类型既不允许复制也不复制的对象)传递给operator<<
函数?
答案 0 :(得分:3)
我不太确定我的答案会有任何帮助,但值得尝试。从您的帖子中,我倾向于认为适当的解决方案是更改convertVariable
的签名。你说这很昂贵,因为有很多专业化,但我认为它实际上是免费的,这取决于你选择“专业化”的方式。
这个article为这类事情提供了一个很好的指导原则:
道德#1:如果你想自定义一个 功能基础模板,并希望如此 定制参与 超载分辨率(或者,永远是 用于完全匹配的情况),make 它是一个普通的旧功能,而不是一个 专业化。而且,如果你提供 超载,避免提供 特。[...]
另一方面,功能模板 专业化不会超载。这个 意味着你的任何专业 写入不会影响哪个模板 被使用,这与什么相反 大多数人都会直观地期待。 毕竟,如果你写了一个 nontemplate函数与 相同的签名而不是 功能模板专业化, nontemplate函数永远是 选择因为它总是如此 被认为是一个比一个更好的匹配 模板强>
实际上,您可以很好地使用重载,而不是专门用于类型UncopyableClass
:
VariableValue convertVariable( const UncopyableClass &t ) { /* ... */ }
这不是专业化,而是过载,它应该完全按预期工作。但请注意,StringBuilder::operator<<
必须采用const引用参数。
答案 1 :(得分:0)
我认为使用此类与使用std::ostream
接口相比没有任何优势。
我有最好的建议是转储类及其错误(例如std::string const& str() const
),并通过适当地为需要流式传输的类重载operator<<
来继续使用流类。 / p>