Domanda

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

È stato utile?

Soluzione

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.

Altri suggerimenti

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top