문제

I am trying to overload the stream operator as a diagnostic tool for various objects in my code. Ideally I would like to be able to modify the stream on the fly with those stream modifier flags, however these are very limited and I don't really want to sprinkle setVerbose flags in each of my objects. I ended up with the following rather poor but working solution

#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;
}

I created the above live example to demonstrate my point, and it prints the following output:

Short Name
Verbose Name
Verbose Name
Short Name

As you can see, I am using a totally inappropriate 'skipws' stream modifier flag as a poor man's 1 level verbose flag - that was just to show the in stream approach I was looking for without havnig to add a member object to each of my printable objects (all suggestions for better approaches would be welcome but I would like to minimize the changes to each of my printable objects - as I have quite a lot). Secondly the flag is persistent until reset later - some other stream flags only last for the next stream operator but I am not exactly sure how that works and thirdly

도움이 되었습니까?

해결책

You can store custom state in your stream instance:

See it 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';
}

Credits go to Dietmar Kühl's answer.

If you needed siginificant amounts of state/logic, you would have to look at imbue-ing a custom locale facet. His answer shows the basics of this approach too.

다른 팁

It seems you are in this case too reluctant to create an abstraction for some reason. Don't take this personally I only write this because I once was too hesitant to do that, but create abstractions. Create a Logger class based on iostream either by inheritance or containment which behavior you can modify. Let's say the logger has options like

enum {SHORT,VERBOSE,DEBUG};

Let this option be static so that it has application wide effect on all the instances. Really there only needs to be one instance perhaps?

I realize that all your printable objects need to support the various printing options in a consistent way, i.e. all need to have shortName and longName.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top