die ganzen Dinge zu tun, ist ein bisschen beteiligt. Um es verständlich zu machen, fange ich mit den grundlegenden Dingen an: Benutzerdefinierte Formatierungsflags für benutzerdefinierte Typen verwenden. Die benutzerdefinierte Formatierung von Ganzzahlen folgt unten.
Die Iostream Klassen ableiten [indirekt] aus std::ios_base
die zwei Speicher für Daten zur Verfügung stellt: std::ios_base::iword()
und std::ios_base::pword()
für int
s und void*
sind. Die Beibehaltung des zugewiesenen Speichers, der mit std::ios_base::pword()
gespeichert wurde, ist nicht trivial und wird glücklicherweise für diesen relativ einfachen Anwendungsfall nicht benötigt. Um diese Funktion zu verwenden, die beide eine nicht-const
Referenz auf den entsprechenden Typ zurückgeben, weisen Sie normalerweise einen Index unter Verwendung std::ios_base::xalloc()
einmal in Ihrem Programm zu und verwenden es wann immer Sie auf Ihre benutzerdefinierten Formatierungsflags zugreifen müssen. Wenn Sie auf einen Wert mit iword()
oder pword()
zugreifen, wird initial Null initialisiert. Um die Dinge zusammen, hier ist ein kleines Programm demonstriert dies:
#include <iostream>
static int const index = std::ios_base::xalloc();
std::ostream& custom(std::ostream& stream) {
stream.iword(index) = 1;
return stream;
}
std::ostream& nocustom(std::ostream& stream) {
stream.iword(index) = 0;
return stream;
}
struct mytype {};
std::ostream& operator<< (std::ostream& out, mytype const&) {
return out << "custom-flag=" << out.iword(index);
}
int main()
{
std::cout << mytype() << '\n';
std::cout << custom;
std::cout << mytype() << '\n';
std::cout << nocustom;
std::cout << mytype() << '\n';
}
Nun wird ein int
wie 4
ist kein benutzer definiert Typ, und es gibt bereits einen Ausgabeoperator für diese definiert. Glücklicherweise können Sie die Art und Weise, in der Ganzzahlen mithilfe von Facetten formatiert werden, genauer anpassen, indem Sie verwenden. Nun, dies zu tun, müssen Sie eine Reihe von Schritten tun:
- Leiten Sie eine Klasse von
std::num_put<char>
und überschreiben die do_put()
Mitglieder, die Sie zu spezialisierten Verhalten geben wollen.
- Erstellen Sie ein
std::locale
Objekt mit der neu erstellten Facette.
std::ios_base::imbue()
der Stream mit dem neuen std::locale
.
Um die Dinge schöner für den Benutzer zu machen, möchten Sie vielleicht ein neues std::locale
mit einer geeigneten std::num_put<char>
Facette heraufbeschwören, wenn der Manipulator verwendet wird. Die mit der Erstellung einer geeigneten Facette jedoch bevor dies zu tun, lassen Sie beginnen:
#include <bitset>
#include <iostream>
#include <limits>
#include <locale>
static int const index = std::ios_base::xalloc();
class num_put
: public std::num_put<char>
{
protected:
iter_type do_put(iter_type to,
std::ios_base& fmt,
char_type fill,
long v) const
{
if (!fmt.iword(index)) {
return std::num_put<char>::do_put(to, fmt, fill, v);
}
else {
std::bitset<std::numeric_limits<long>::digits> bits(v);
size_t i(bits.size());
while (1u < i && !bits[i - 1]) {
--i;
}
for (; 0u < i; --i, ++to) {
*to = bits[i - 1]? '1': '0';
}
return to;
}
}
#if 0
// These might need to be added, too:
iter_type do_put(iter_type, std::ios_base&, char_type,
long long) const;
iter_type do_put(iter_type, std::ios_base&, char_type,
unsigned long) const;
iter_type do_put(iter_type, std::ios_base&, char_type,
unsigned long long) const;
#endif
};
std::ostream& custom(std::ostream& stream) {
stream.iword(index) = 1;
return stream;
}
std::ostream& nocustom(std::ostream& stream) {
stream.iword(index) = 0;
return stream;
}
int main()
{
std::locale loc(std::locale(), new num_put);
std::cout.imbue(loc);
std::cout << 13 << '\n';
std::cout << custom;
std::cout << 13 << '\n';
std::cout << nocustom;
std::cout << 13 << '\n';
}
Was ein bisschen hässlich ist, ist, dass es notwendig zu imbue()
der Brauch std::locale
die custom
Manipulator zu verwenden. Um werde diese los zu werden, können wir nur sicherstellen, dass die individuelle Facette in den verwendeten std::locale
installiert ist, und, wenn dies nicht der Fall, nur um es zu installieren, wenn das Flag gesetzt:
std::ostream& custom(std::ostream& stream) {
if (!stream.iword(index)
&& 0 == dynamic_cast<num_put const*>(
&std::use_facet<std::num_put<char> >(stream.getloc()))) {
stream.imbue(std::locale(stream.getloc(), new num_put));
}
stream.iword(index) = 1;
return stream;
}
Was nun bleibt, ist auch überschreiben die verschiedenen do_put()
Mitglieder ordnungsgemäß mit den verschiedenen unsigned
Typen und mit long long
arbeiten, aber das ist als Übung übrig.
Ich würde den 'nobinary' Begriff töten und sie' std :: dec' usw. verwenden lassen. – chris
Möchten Sie, dass es auch nach dem Ende der Aussage bleibt? –
BTW, [nicht verwenden Sie 'std :: endl'] (http://kuhllib.com/2012/01/14/stop-excessive-use-of-stdendl/). –