代码之家  ›  专栏  ›  技术社区  ›  UltraInstinct

操作std::cout后恢复其状态

  •  80
  • UltraInstinct  · 技术社区  · 15 年前

    假设我有这样一个代码:

    void printHex(std::ostream& x){
        x<<std::hex<<123;
    }
    ..
    int main(){
        std::cout<<100; // prints 100 base 10
        printHex(std::cout); //prints 123 in hex
        std::cout<<73; //problem! prints 73 in hex..
    }
    

    我的问题是,是否有任何方法可以“恢复”经济的状态 cout 从函数返回后恢复到其原始值(有点像 std::boolalpha std::noboolalpha ..) ?

    6 回复  |  直到 5 年前
        1
  •  112
  •   Dev Null Richard Hodges    5 年前

    你需要 #include <iostream> #include <ios> 然后在需要时:

    std::ios_base::fmtflags f( cout.flags() );
    
    //Your code here...
    
    cout.flags( f );
    

    你可以把这些放在函数的开头和结尾,或者签出 this answer 关于如何将此与 RAII

        2
  •  63
  •   C. K. Young    15 年前

    这个 Boost IO Stream State Saver 似乎正是您所需要的。:-)

    基于代码段的示例:

    void printHex(std::ostream& x) {
        boost::io::ios_flags_saver ifs(x);
        x << std::hex << 123;
    }
    
        3
  •  55
  •   rr-    9 年前

    请注意,此处提供的答案不会恢复 std::cout . 例如 std::setfill .flags() . 更好的解决办法是使用 .copyfmt :

    std::ios oldState(nullptr);
    oldState.copyfmt(std::cout);
    
    std::cout
        << std::hex
        << std::setw(8)
        << std::setfill('0')
        << 0xDECEA5ED
        << std::endl;
    
    std::cout.copyfmt(oldState);
    
    std::cout
        << std::setw(15)
        << std::left
        << "case closed"
        << std::endl;
    

    将打印:

    case closed
    

    而不是:

    case closed0000
    
        4
  •  22
  •   qbert220    11 年前

    class IosFlagSaver {
    public:
        explicit IosFlagSaver(std::ostream& _ios):
            ios(_ios),
            f(_ios.flags()) {
        }
        ~IosFlagSaver() {
            ios.flags(f);
        }
    
        IosFlagSaver(const IosFlagSaver &rhs) = delete;
        IosFlagSaver& operator= (const IosFlagSaver& rhs) = delete;
    
    private:
        std::ostream& ios;
        std::ios::fmtflags f;
    };
    

    void f(int i) {
        IosFlagSaver iosfs(std::cout);
    
        std::cout << i << " " << std::hex << i << " ";
        if (i < 100) {
            std::cout << std::endl;
            return;
        }
        std::cout << std::oct << i << std::endl;
    }
    
        5
  •  11
  •   n.caillou    6 年前

    您可以围绕标准输出缓冲区创建另一个包装:

    #include <iostream>
    #include <iomanip>
    int main() {
        int x = 76;
        std::ostream hexcout (std::cout.rdbuf());
        hexcout << std::hex;
        std::cout << x << "\n"; // still "76"
        hexcout << x << "\n";   // "4c"
    }
    

    void print(std::ostream& os) {
        std::ostream copy (os.rdbuf());
        copy << std::hex;
        copy << 123;
    }
    

    ios 对象(但不是缓冲区),包括一些您正在付费但不太可能使用的内容,例如区域设置。

    否则我觉得如果你要用 .flags() 最好保持一致并使用 .setf() 不如 << 语法(纯粹的风格问题)。

    void print(std::ostream& os) {
        std::ios::fmtflags os_flags (os.flags());
        os.setf(std::ios::hex);
        os << 123;
        os.flags(os_flags);
    }
    

    正如其他人所说,您可以将上述(和 .precision() .fill() ,但通常不包括与语言环境和单词相关的内容,这些内容通常不会被修改,而且更重),以方便使用并确保异常安全;构造函数应该接受 std::ios& .

        6
  •  9
  •   ledonter    7 年前

    void printHex(std::ostream& x) {
       ios::fmtflags f(x.flags());
       x << std::hex << 123 << "\n";
       x.flags(f);
    }
    
    int main() {
        std::cout << 100 << "\n"; // prints 100 base 10
        printHex(std::cout);      // prints 123 in hex
        std::cout << 73 << "\n";  // problem! prints 73 in hex..
    }
    
        7
  •  6
  •   Ciro Santilli OurBigBook.com    4 年前

    C++20 std::format 在大多数情况下,将是保存还原的最佳选择

    一旦您可以使用它,您将能够简单地将十六进制写为:

    #include <format>
    #include <string>
    
    int main() {
        std::cout << std::format("{x} {#x} {}\n", 16, 17, 18);
    }
    

    预期产出:

    10 0x11 18
    

    std::cout 国家。

    C++ cout hex values?

        8
  •  0
  •   J. Wilde    4 年前

    我想概括一下qbert220的答案:

    #include <ios>
    
    class IoStreamFlagsRestorer
    {
    public:
        IoStreamFlagsRestorer(std::ios_base & ioStream)
            : ioStream_(ioStream)
            , flags_(ioStream_.flags())
        {
        }
    
        ~IoStreamFlagsRestorer()
        {
            ioStream_.flags(flags_);
        }
    
    private:
        std::ios_base & ioStream_;
        std::ios_base::fmtflags const flags_;
    };
    

    PS:我想对上述答案做一个简单的评论,但是stackoverflow不允许我这么做,因为缺少声誉。因此,让我在这里混乱的答案,而不是一个简单的评论。。。

        9
  •  0
  •   aGuegu    3 年前

    不是将格式注入cout,而是 << 领养 setf unsetf

    void printHex(std::ostream& x){
      x.setf(std::ios::hex, std::ios::basefield);
      x << 123;
      x.unsetf(std::ios::basefield);
    }
    

    ios_基本名称空间也可以正常工作

    void printHex(std::ostream& x){
      x.setf(std::ios_base::hex, std::ios_base::basefield);
      x << 123;
      x.unsetf(std::ios_base::basefield);
    }
    

    参考: http://www.cplusplus.com/reference/ios/ios_base/setf/