【问题标题】:boost::lexical_cast and stringification of non-builtin typesboost::lexical_cast 和非内置类型的字符串化
【发布时间】:2012-01-19 10:05:59
【问题描述】:

关于复合类型的 boost::lexical_cast(在我的情况下为 std::vector)我有一个(可能)简单的问题。

我的第一个模板化字符串化函数版本如下

template <typename T>
std::string stringiy(const T &t)
{
std::ostringstream o;
o<< t;
return o.str();
}

一个工作示例如下:

vector<int> x(10,-3;
cout << stringify<vector<int> >(x) << endl;

与输出 "-3-3-3-3-3-3-3-3"~ 但出于性能原因,我想利用boost::lexical_cast

现在我更改了函数实现:

template <typename T>
std::string stringiy(const T &t)
{
   return boost::lexical_cast<string>(t);
}

虽然此方法适用于内置类型,但当它用于 std::vector 时,它将停止适用于前一种情况。

如果为向量创建专门的模板,问题仍然存在(无法编译)

template <typename T>
std::string stringiy(const std::vector<T> &t)
{
     vector<string> strret = num2str(t);
     string r;
     for ( vector<string>::iterator iter = strret.begin(); iter!=strret.end(); ++iter )
    r.append(*iter);
     return r;
}

有什么建议吗?

g++-4.5,ubuntu 11.10 amd64

In file included from Util.h:41:0,
                 from testLexicalCast.cpp:49:
/usr/include/boost/lexical_cast.hpp: In member function ‘bool boost::detail::lexical_stream<Target, Source, Traits>::operator<<(const Source&) [with Target = std::basic_string<char>, Source = std::vector<double>, Traits = std::char_traits<char>]’:
/usr/include/boost/lexical_cast.hpp:1151:13:   instantiated from ‘Target boost::detail::lexical_cast(typename boost::call_traits<Source>::param_type, CharT*, size_t) [with Target = std::basic_string<char>, Source = std::vector<double>, bool Unlimited = true, CharT = char, typename boost::call_traits<Source>::param_type = const std::vector<double>&, size_t = long unsigned int]’
/usr/include/boost/lexical_cast.hpp:1174:77:   instantiated from ‘Target boost::lexical_cast(const Source&) [with Target = std::basic_string<char>, Source = std::vector<double>]’
Util.h:211:43:   instantiated from ‘std::string util::stringify(const T&) [with T = std::vector<double>, std::string = std::basic_string<char>]’
testLexicalCast.cpp:72:53:   instantiated from here
/usr/include/boost/lexical_cast.hpp:595:48: error: no match for ‘operator<<’ in ‘((boost::detail::lexical_stream<std::basic_string<char>, std::vector<double>, std::char_traits<char> >*)this)->boost::detail::lexical_stream<std::basic_string<char>, std::vector<double>, std::char_traits<char> >::stream << input’
/usr/include/c++/4.5/ostream:108:7: note: candidates are: std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__ostream_type& (*)(std::basic_ostream<_CharT, _Traits>::__ostream_type&)) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.5/ostream:117:7: note:                 std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__ios_type& (*)(std::basic_ostream<_CharT, _Traits>::__ios_type&)) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>, std::basic_ostream<_CharT, _Traits>::__ios_type = std::basic_ios<char>]
/usr/include/c++/4.5/ostream:127:7: note:                 std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(std::ios_base& (*)(std::ios_base&)) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.5/ostream:165:7: note:                 std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long int) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.5/ostream:169:7: note:                 std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long unsigned int) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.5/ostream:173:7: note:                 std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(bool) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.5/bits/ostream.tcc:91:5: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(short int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/include/c++/4.5/ostream:180:7: note:                 std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(short unsigned int) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.5/bits/ostream.tcc:105:5: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(int) [with _CharT = char, _Traits = std::char_traits<char>]
/usr/include/c++/4.5/ostream:191:7: note:                 std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(unsigned int) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.5/ostream:200:7: note:                 std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long long int) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.5/ostream:204:7: note:                 std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long long unsigned int) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.5/ostream:209:7: note:                 std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(double) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.5/ostream:213:7: note:                 std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(float) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.5/ostream:221:7: note:                 std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(long double) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.5/ostream:225:7: note:                 std::basic_ostream<_CharT, _Traits>::__ostream_type& std::basic_ostream<_CharT, _Traits>::operator<<(const void*) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__ostream_type = std::basic_ostream<char>]
/usr/include/c++/4.5/bits/ostream.tcc:119:5: note:                 std::basic_ostream<_CharT, _Traits>& std::basic_ostream<_CharT, _Traits>::operator<<(std::basic_ostream<_CharT, _Traits>::__streambuf_type*) [with _CharT = char, _Traits = std::char_traits<char>, std::basic_ostream<_CharT, _Traits>::__streambuf_type = std::basic_streambuf<char>]
make: *** [testLexicalCast.o] Error 1

【问题讨论】:

  • 附注我忘了告诉你我有一个重载的运算符 std::vector 所以ostringstream 的第一个方法有效
  • 您能否发布您收到的确切错误消息?
  • 难道不是因为vector的实际实现更像vector

标签: c++ templates boost stringify lexical-cast


【解决方案1】:

我可能会离开这里,但我个人认为你最好不要尝试对一个容器进行字符串化,而是为所有容器创建一个“序列化”方法。

编辑:已修复

template<typename Container>
   std::string serialize_container(const Container& container)
{
     std::stringstream ss;
     std::copy(container.begin(), container.end(),    
              std::ostream_iterator<typename Container::value_type>(ss,"-"));
     return ss.str();    
}

编辑:也就是说,如果你想使用带有 stringify 的向量,那么你可以这样做。

template <typename T, typename A=void>
std::string stringiy(const T& t)
{
    //...
} 

template <typename T, typename A>
std::string stringiy(const std::vector<T, A>& container)
{
     std::stringstream ss;

     //if << is overloaded for vector
     ss << container;

     /*//else
     std::copy(container.begin(), container.end(),
               std::ostream_iterator<T>(ss,"-"));    
     //        std::ostream_iterator<typename Container::value_type>(ss,"-"));
     */
     return ss.str();    
}

NB 未经测试,但这是要点。

【讨论】:

  • 您的解决方案无法编译...Util.h: In function 'std::string util::serialize_container(const T&)': Util.h:219:104: error: template argument 1 无效
  • 糟糕的是我使用了对象而不是类型,请参阅 std::copy 的最后一个参数。
  • 完美,这可以完成工作,但使用此解决方案,我必须指定两个版本的 stringify 并且它不使用 boost::lexical_cast 从 double 转换时它具有更高的精度。在任何情况下,您都是一个很好的答案,谢谢!
  • 静态区分模板输入类型与容器或内置类型是否有意义?
  • 我个人更喜欢使用 value_type,模板很棒但是太多了,它们会变得混乱。也就是说,如果您想确保该函数仅采用任何类型的向量,那么无论如何您都必须拥有 T 和 A,在这种情况下使用它们,因为它们更简洁且不那么冗长 - 只需 T 而不是 @ 987654325@
【解决方案2】:

您可能已经在全局命名空间中为向量声明了operator&lt;&lt;,而boost::lexical_cast 只会在boost:: 命名空间和std:: 命名空间中查找,其中定义了ostream。 尝试通过将 operator&lt;&lt; 的声明和定义包装在 namespace std { ... } 中,将重载添加到 std:: 命名空间。

【讨论】:

  • 是的!没错,这绝对是最好的解决方案,我将重载的运算符
  • @111111 是的,确实如此,但参数是 std::vectorstd::ostream,因此 ADL 在 std 命名空间中查找。
  • @wolfgang,这当然可以解释。我不知道你怎么想,但不会向 std 命名空间添加一点点 jank(如果不是非法的话)?
  • @111111 我认为有一些官方允许的例外情况。我清楚地记得,明确允许将 std::swap 的重载添加到 std:: 命名空间,我希望 operator 也是如此
  • @wolfgang:您专门使用模板进行交换,而不是提供新的重载。一般建议再次将 ADL 与交换一起使用。我认为如果它可以将其添加到提升中,那将是最好的。出于兴趣,您知道如果您在本地命名空间中使用 op
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-18
  • 2018-06-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-20
相关资源
最近更新 更多