Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.2k views
in Technique[技术] by (71.8m points)

string - Custom manipulator for C++ iostream

I'd like to implement a custom manipulator for ostream to do some manipulation on the next item being inserted into the stream. For example, let's say I have a custom manipulator quote:

std::ostringstream os;
std::string name("Joe");
os << "SELECT * FROM customers WHERE name = " << quote << name;  

The manipulator quote will quote name to produce:

SELECT * FROM customers WHERE name = 'Joe'

How do I go about accomplishing that? Thanks.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

It's particularly difficult to add a manipulator to a C++ stream, as one has no control of how the manipulator is used. One can imbue a new locale into a stream, which has a facet installed that controls how numbers are printed - but not how strings are output. And then the problem would still be how to store the quoting state safely into the stream.

Strings are output using an operator defined in the std namespace. If you want to change the way those are printed, yet keeping the look of manipulators, you can create a proxy class:

namespace quoting {
struct quoting_proxy {
    explicit quoting_proxy(std::ostream & os):os(os){}

    template<typename Rhs>
    friend std::ostream & operator<<(quoting_proxy const& q, 
                                     Rhs const& rhs) {
        return q.os << rhs;
    }

    friend std::ostream & operator<<(quoting_proxy const& q, 
                                     std::string const& rhs) {
        return q.os << "'" << rhs << "'";
    }

    friend std::ostream & operator<<(quoting_proxy const& q, 
                                     char const* rhs) {
        return q.os << "'" << rhs << "'";
    }
private:
    std::ostream & os;
};

struct quoting_creator { } quote;
quoting_proxy operator<<(std::ostream & os, quoting_creator) {
    return quoting_proxy(os);
}
}

int main() {
    std::cout << quoting::quote << "hello" << std::endl; 
}

Which would be suitable to be used for ostream. If you want to generalize, you can make it a template too and also accept basic_stream instead of plain string. It has different behaviors to standard manipulators in some cases. Because it works by returning the proxy object, it will not work for cases like

std::cout << quoting::quote; 
std::cout << "hello";

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...