使用ostream标志作为详细调试标志

时间:2014-05-08 18:02:34

标签: c++ logging outputstream cout

我正在尝试将流操作符重载为我代码中各种对象的诊断工具。理想情况下,我希望能够使用这些流修改器标志动态修改流,但是这些非常有限,我并不想在每个对象中撒上setVerbose标志。我最终得到了以下相当差但工作正常的解决方案

#include <iostream>
#include <string>
#include <vector>

struct StructA {
    std::string mLongName;
    std::string mShortName;
    inline friend std::ostream& operator << (std::ostream& os, const StructA& rStruct) {
        // I dont know how to use a generic verbose flag - so use this - very bad idea 
        // but perhaps the stackoverflow people can help out with a good suggestion
        if (os.flags() & os.skipws) {
            os << rStruct.mShortName << std::endl;
        } else {
            os << rStruct.mLongName << std::endl;
        }
        return os;
    }
};

int main()
{
    StructA test {"Verbose Name", "Short Name"};
    std::cout << test  << std::noskipws << test << test << std::skipws << test;
}

我创建了上面的live example来演示我的观点,并打印出以下输出:

Short Name
Verbose Name
Verbose Name
Short Name

正如你所看到的,我正在使用一个完全不合适的&#39; skipws&#39; stream modifier标志作为一个穷人的1级详细标志 - 这只是为了显示我正在寻找的in stream方法而没有havnig为我的每个可打印对象添加一个成员对象(所有建议更好的方法将是欢迎,但我想尽量减少每个可打印对象的更改 - 因为我有很多)。其次,该标志是持久的,直到稍后重置 - 其他一些流标志仅持续下一个流操作符,但我不确定它是如何工作的,第三个

2 个答案:

答案 0 :(得分:2)

在这种情况下,您似乎也不愿意出于某种原因创建抽象。不要单独接受这个我只写这个,因为我曾经太犹豫不决,但创建抽象。通过继承或包含您可以修改的行为,基于iostream创建Logger类。假设记录器有像

这样的选项
enum {SHORT,VERBOSE,DEBUG};

让此选项为静态,以便它对所有实例具有应用程序范围的影响。真的只需要一个实例吗?

我意识到所有可打印对象都需要以一致的方式支持各种打印选项,即所有都需要shortName和longName。

答案 1 :(得分:2)

您可以在流实例中存储自定义状态:

查看 Live On Coliru

#include <iostream>

static int const index = std::ios_base::xalloc();

std::ostream& verbose(std::ostream& stream) {
    stream.iword(index) = 1;
    return stream;
}

std::ostream& noverbose(std::ostream& stream) {
    stream.iword(index) = 0;
    return stream;
}

struct StructA {
    std::string mLongName;
    std::string mShortName;

    inline friend std::ostream& operator << (std::ostream& os, const StructA& rStruct) {
        switch (os.iword(index)) {
            case 1:  return os << rStruct.mLongName;
            case 0:
            default: return os << rStruct.mShortName;
        }
    }
};

int main()
{
    StructA a;
    a.mLongName = "loooooooooooooooooooong names are tedious";
    a.mShortName = "succinctness";

    std::cout << a          << '\n';

    std::cout << verbose;
    std::cout << a          << '\n';

    std::cout << noverbose;
    std::cout << a          << '\n';
}

积分转到Dietmar Kühl's answer

如果您需要大量的状态/逻辑,则必须考虑灌输自定义区域设置方面。他的回答也显示了这种方法的基础。