zoukankan      html  css  js  c++  java
  • C++学习(二):学会使用stringstream

    1.前言 

      今天在CppTemplateTutorial群里,有人问了一个问题:这一堆add怎么简化掉 https://wandbox.org/permlink/vDPDwMFbBIQSSymS。代码如下:

     1 #include <variant>
     2 #include <map>
     3 #include <string>
     4 #include <cassert>
     5 #include <iostream>
     6 struct myval : public std::variant<int, double, std::string>
     7 {
     8     using base = std::variant<int, double, std::string>;
     9     myval() : base() {}
    10     myval(int v) : base(v) {}
    11     myval(double v) : base(v) {}
    12     myval(std::string v) : base(v) {}
    13     
    14     myval(myval const& v) : base(v) {}
    15     myval(myval&& v) : base(std::move(v)) {}
    16 };
    17 
    18 template<class T, class U>
    19 myval add(T const& a, U const& b) {
    20     return a + b;
    21 }
    22 
    23 myval add(std::string const& a, int b) {
    24     return a + std::to_string(b);
    25 }
    26 myval add(std::string const& a, double b) {
    27     return a + std::to_string(b);
    28 }
    29 myval add(std::string const& a, std::string const& b) {
    30     return a + b;
    31 }
    32 
    33 myval add(int a, std::string const& b) {
    34     return std::to_string(a) + b;
    35 }
    36 myval add(double a, std::string const& b) {
    37     return std::to_string(a) + b;
    38 }
    39 
    40 myval operator+(myval const& a, myval const& b)
    41 {
    42     return std::visit([](auto& a, auto& b) { return add(a, b); }, a, b);
    43 }
    44 
    45 std::ostream& operator<<(std::ostream& os, myval const& b)
    46 {
    47     return std::visit([&](auto b)->std::ostream& { os << b; return os; }, b);
    48 }
    49 
    50 int main() {
    51     myval a = 1;
    52     myval b = 10.0;
    53     myval c = a + b;
    54     std::map<std::string, myval> m{{"1", a}, {"2", b}, {"3", c}};
    55     if (m.find("3") == m.end())
    56     {
    57         std::cout << m["3"];
    58     }
    59 }
    View Code

      一种解决方法是:给to_string加个string重载,不过这并不是最好的办法。另一种方法是使用stringstream。不过,想到前一段时间,我还经常用C语言的sprintf,我突然觉得有点好笑。

      处理问题的优先方式应该是充分考虑语言的特性,使得问题处理起来更加简洁高效一点。学会使用stringstream,可以避免一些由C语言中类似atoi,itoa ,strtol以及sprintf带来的问题。

      那么,这个问题如果使用stringstream可以这样写:

      

    2.使用stringstream对象简化类型转换

      C++标准库中的<sstream>提供了比ANSI C的<stdio.h>更高级的一些功能,即单纯性、类型安全和可扩展性。

      为什么要学习stringstream。如果你已习惯了<stdio.h>风格的转换,也许你首先会问:为什么要花额外的精力来学习基于<sstream>的类型转换呢?也许对下面一个简单的例子的回顾能够说服你。假设你想用sprintf()函数将一个变量从int类型转换到字符串类型。为了正确地完成这个任务,你必须确保证目标缓冲区有足够大空间以容纳转换完的字符串。此外,还必须使用正确的格式化符。如果使用了不正确的格式化符,会导致非预知的后果。下面是一个例子:

    int n=10000; chars[10]; sprintf(s,"%d",n);// s中的内容为"10000" 

      到目前为止看起来还不错。但是,对上面代码的一个微小的改变就会使程序崩溃: 

    int n=10000;char s[10];sprintf(s,"%f",n);// 看!错误的格式化符 

      在这种情况下,程序员错误地使用了%f格式化符来替代了%d。因此,s在调用完sprintf()后包含了一个不确定的字符串。要是能自动推导出正确的类型,那不是更好吗?

      <sstream>库定义了三种类:istringstream、ostringstream和stringstream,分别用来进行流的输入、输出和输入输出操作。另外,每个类都有一个对应的宽字符集版本。简单起见,我主要以stringstream为中心,因为每个转换都要涉及到输入和输出操作。
      注意,<sstream>使用string对象来代替字符数组。这样可以避免缓冲区溢出的危险。而且,传入参数和目标对象的类型被自动推导出来,即使使用了不正确的格式化符也没有危险。

      在过去留下来的程序代码和纯粹的C程序中,传统的<stdio.h>形式的转换伴随了我们很长的一段时间。但是,如文中所述,基于stringstream的转换拥有类型安全和不会溢出这样抢眼的特性,使我们有充足得理由抛弃<stdio.h>而使用<sstream>。<sstream>库还提供了另外一个特性—可扩展性。你可以通过重载来支持自定义类型间的转换。

    3.参考来源:

      http://www.cppblog.com/Sandywin/archive/2007/07/13/27984.html

      http://developer.zhiding.cn/2003/0304/83252.shtml

        http://www.cnblogs.com/gamesky/archive/2013/01/09/2852356.html

      http://www.cnblogs.com/james6176/p/3222671.html

      http://www.cnblogs.com/lzjsky/archive/2011/01/04/1925538.html 

  • 相关阅读:
    java语法基础(总结)
    ZookeeperclientAPI之创建会话(六)
    对A轮的追逐变得越加狂热,当前距离互联网泡沫到底有多近?
    Java集合(一):Java集合概述
    深入了解Cookie(1)------selenium2进行Cookie操作的前奏
    Cocos2d-X开发中国象棋《九》走棋规则
    java中request,application,session三个域及参数简单示例
    在多浏览器使用JS复制内容到剪切板,无需插件
    初学structs2,结果类型简单示例
    使用servletAPI三种方式简单示例
  • 原文地址:https://www.cnblogs.com/wurui1994/p/6799195.html
Copyright © 2011-2022 走看看