我的代码可以使用'T'或'const T&'专业化,哪个可用?

时间:2010-11-15 12:07:23

标签: c++ templates

我们正在使用一个内部库,其中包含一个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<<函数?

2 个答案:

答案 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>