为了测试和显示我的库的某些功能的结果,我正在创建一组方便的功能。
我有一个execute
函数,如下所示:
template <typename R, typename I>
std::string execute( const std::string& func_name, R(*func_ptr)( const I& ), const I& func_input );
它调用该函数,并以格式化的字符串显示结果和参数,我可以将其发送到std::cout
。
问题是我的一些函数没有返回 convertible-to-string 结果。我以为我可以简单地用例如:
重载全局::operator std::string
template <typename T>
operator std::string( const std::vector<T>& v );
但是GCC抱怨说:
error: 'operator std::string(const std::vector<T, std::allocator<_CharT> >&)' must be a nonstatic member function
嗯,问题当然是我无法将成员运算符添加到std::vector
,甚至对于我的类,我也不想用“进行测试”转换来污染它们运算符。
我想我可以添加一个间接层并使用函数而不是转换运算符,但这不是更美观的解决方案。我也可以为::operator <<
重载std::ostream
并使用std::ostringstream
,但这也不是最干净的解决方案。
我想知道全局转换运算符是否真的不可重载,如果是,为什么。
答案 0 :(得分:12)
转换运算符(强制转换运算符)必须是生成转换类型的可转换类的成员。作为赋值运算符,它们必须是成员函数,正如编译器告诉你的那样。
根据您希望将多少工作量放入调试部分,您可以尝试使用元编程将执行方法转发到不同的实际实现,为打印内容的容器提供特定的实现。
为什么不为您的类型提供operator<<
?我认为这实际上是惯用的解决方案。与使用转换为字符串以生成可打印结果的方法的其他语言不同,在C ++中,惯用方法是提供operator<<
,然后使用stringstreams
(或boost::lexical_cast
或类似的解决方案)进行转换基于operator<<
实现的字符串。有一个简单的实用工具类here可以从覆盖string
的元素创建operator<<
,如果您想将其用作起点。
答案 1 :(得分:5)
我想知道全局转换运算符是否真的不可重载,如果是,为什么。
不,没有这样的事情。转换函数必须是类的成员。如果不是这样,那么通过引入歧义会使重载决策成为编译器特别棘手的问题。
答案 2 :(得分:1)
没有用户定义的全局转换运算符。您必须控制目标类型(在这种情况下,非显式的一个参数构造函数是转换运算符)或源类型(在这种情况下,您必须重载成员运算符target())。
答案 3 :(得分:0)
转换函数必须是成员函数。该函数可能未指定返回类型,参数列表必须为空。它们应该谨慎使用,并且应该有一种从一种类型到另一种类型的明确转换路径。否则会导致意外结果和神秘错误。
答案 4 :(得分:0)
不幸的是,没有全球演员运营商这样的东西。出奇。但模板是你的朋友。
有时您不希望将转换暴露给接口,而是希望仅为特定实现保持匿名。我通常在类中添加一个模板as()方法,它也可以在强制转换等中进行类型检查,并让你处理你想要实现强制转换的方式(例如dynamic,shared,ref等)。
这样的事情:
template< class EvtT >const EvtT& as() const throw( std::exception )
{
const EvtT* userData = static_cast<const EvtT*>( m_UserData );
ASSERT( userData, "Fatal error! No platform specific user data in input event!" );
return *userData;
}
m_UserData是一种匿名类型,只有实现知道。虽然这是严格的非类型转换(我不在这里使用类型cecks),但可以用dynamic_cast和正确的转换异常替换它。
实施只是这样做:
unsigned char GetRawKey( const InputEvent& ie )
{
const UserEvent& ue = ie.as<const UserEvent>();
...