.TH "FBB::CSVTable" "3bobcat" "2005\-2020" "libbobcat\-dev_5\&.07\&.00" "Table Construction" .PP .SH "NAME" FBB::CSVTable \- sequentially fills tables row\-wise .PP .SH "SYNOPSIS" \fB#include \fP .br Linking option: \fI\-lbobcat\fP .PP .SH "DESCRIPTION" .PP \fBFBB::CSVTable\fP is used to fill tables row\-wise\&. By default the table\(cq\&s elements are comma\-separated\&. The elements may contain any type of data that can also be inserted into \fIstd::ostreams\fP, as may also contain horizontal lines (optionally spanning multiple columns)\&. .PP Before inserting elements into the table the widths, alignment types and precisions of the table\(cq\&s columns are defined\&. By default values are right\-aligned\&. While inserting table elements the alignment types and precisions may be altered for specific elements, optionally spanning multiple columns\&. When inserting values whose representations require more characters than the current widths of the columns receiving those values then those larger widths take precedence over the defined column widths\&. .PP Different from tables defined by \fBFBB::Table\fP(3bobcat) all data inserted into \fBCSVTables\fP do not have to be completely available before the table is inserted into a destination \fIstd::ostream\fP\&. As the table\(cq\&s column formats are known before entering the data the \fBCSVTable\fP knows which format to use for which column\&. These column format specifications may be defined in multiple ways, e\&.g\&., by using text labels and values\&. \fBCSVTable\fP objects always use the widest column specifications and alignment types that were specified last\&. .PP When inserting elements into \fBCSVTables\fP the standard \fBC++\fP IO manipulators can also be used\&. Table rows do not automatically end after the table\(cq\&s last column has been filled\&. But when inserting elements beyond the last column they are inserted as\-is (but then the standard I/O format specifications can optionally be used)\&. .PP Table column definitions and table rows end at the end of insertion statements (see below at the descriptions of the various \fIoperator<<\fP functions)\&. .PP \fBCSVTable\fP uses two support classes handling, respectively, the definitions of the characteristics of the table\(cq\&s columns and inserting values into the table\(cq\&s elements\&. \fBCSVTabDef\fP handles the table\(cq\&s column definitions, \fBCSVTabIns\fP handles insertions into the table elements\&. Their main characteristics are various insertion operators which are described below\&. .PP Constructing tables normally consists of two steps: first the characteristics of the columns are defined, then values are inserted into the table\(cq\&s elements\&. This sequence is not enforced by \fBCSVTable\fP: after inserting values into the table column definitions may be updated, whereafter additional values may be inserted into the table which then use the updated column definitions\&. .PP .SH "NAMESPACE" \fBFBB\fP .br All constructors, members, operators and manipulators, mentioned in this man\-page, are defined in the namespace \fBFBB\fP\&. .PP .SH "INHERITS FROM" \- .PP .SH "FMT" .PP \fBFMT\fP objects are returned by several free functions (like \fBleft\fP, described below in section \fBFREE FUNCTIONS\fP), and \fBFMT\fP defines the enumeration \fIAlign\fP (see the next section) specifying alignment types\&. \fBFMT\fP objects are internally used by \fBCSVTable\fP objects\&. A \fBFMT\fP object specifies the width, the precision when floating point numbers are inserted, the column\(cq\&s alignment type (left, right or centered), and the number of table columns to use\&. .PP \fBFMT\fP objects can be inserted into \fIstd::ostream\fP objects showing its characteristics\&. In addition it offers the following (const) accessors: .IP o \fBFMT::Align align()\fP: .br the alignment value; .IP o \fBunsigned nCols()\fP: .br the number of occupied columns; .IP o \fBunsigned precision()\fP: .br the precision used when inserting a floating point value (\fI~0U\fP (= \-1 as \fIint\fP) is returned if \fIprecision\fP is not used)\&. The insertion operator shows \fIprecision: \-1\fP when precision is \fI~0U\fP; .IP o \fBunsigned width()\fP: .br the width in number of characters; .PP The static member \fBchar const *FMT::align(FMT::Align value)\fP returns the textual label corresponding to \fIvalue\fP\&. .PP .SH "ALIGN ENUM" .PP The \fIenum FMT::Align\fP defines the following values indicating the alignment types of the columns of the table: .IP o \fBFMT::Align::CENTER\fP: .br The information inserted in the column is centered; .IP o \fBFMT::Align::LEFT\fP: .br The information inserted in the column is left\-aligned; .IP o \fBFMT::Align::RIGHT\fP: .br The information inserted in the column is right\-aligned (this is the alignment used by default); .PP In addition, when inserting horizontal lines, the value \fBFMT::Align::HLINE\fP is used\&. .PP .SH "CONSTRUCTORS" .IP o \fBCSVTable(std::ostream &out = std::cout, std::string const &sep = \(dq\&, \(dq\&)\fP: .br This constructor by default writes its table to \fIstd::cout\fP and uses a comma followed by a space character as column separator\&. During the table\(cq\&s construction the stream to write the table to can be altered using the \fIstream\fP members, and the separator can be changed using the \fIsep\fP member, but the separator can also be changed while filling the table\(cq\&s elements (see below)\&. When the \fBCSVTable\fP object goes out of scope the stream\(cq\&s original configuration is restored; .IP .IP o \fBCSVTable(std::ofstream &&tmp, std::string const &sep = \(dq\&, \(dq\&)\fP: .br This constructor by default uses the same separator to separate the column\(cq\&s elements as the first constructor, but writes the table to the \fIofstream tmp\fP, which is grabbed by \fICSVTable\fP; .IP .IP o \fBCSVTable(std::string const &fname, std::string const &sep = \(dq\&, \(dq\&), std::ios::openmode mode = ios::out\fP: .br This constructor by default uses the same separator to separate the column\(cq\&s elements as the first constructor, but writes the table to the file having (path)name \fIfname\fP, by default (re)writing the file\&. If the file already exists and \fICSVTable\fP should start writing at the file\(cq\&s end use, e\&.g\&., \fIios::ate | ios::in\fP\&. An exception is thrown if the specified file cannot be opened\&. .PP The move constructor and assignment operator are available; the copy constructor and assignment operator are not available\&. .PP .SH "OVERLOADED OPERATORS" .PP In the provided examples \fItab\fP refers to an existing \fBCSVTable\fP object\&. Each insertion statement (note: not insertion \fIexpression\fP) either defines or updates the table columns\(cq\& definitions or fills the next row of the table with data\&. .PP \fBDefining column characteristics\fP .PP The return types and left\-hand side operands of the following insertion operators are specified as \fBCSVTabDef\fP\&. The member \fBfmt()\fP (cf\&. section \fBMEMBER FUNCTIONS\fP) returns a \fBCSVTabDef\fP object which is then used in combination with the following insertion operators to define the characteristics of the table\(cq\&s columns\&. .PP .IP o \fBCSVTabDef &operator<<(CSVTabDef &tab, FMT const &fmt)\fP: .br This insertion operator defines the characteristics of the next table column\&. \fBFMT\fP objects inserted into \fBCSVTabDef\fP objects must have been returned by \fBcenter, left\fP or \fBright\fP (see section \fBFREE FUNCTIONS\fP, below), or an exception will be thrown\&. When redefining column specifications (e\&.g\&., when inserting \fBFMT\fP objects for previously defined columns) then the width of the wider column is used\&. Example: .nf // left align using 10 char\&. positions: tab\&.fmt() << FBB::left(10); // 1st col now right aligned, but its // width remains 10 tab\&.fmr() << FBB::right(4); .fi .IP .IP o \fBCSVTabDef &operator<<(CSVTabDef &tab, Insertable const &value)\fP: .br This operator is defined for the template type \fIInsertable\fP parameter \fIvalue\fP, where \fIvalue\(cq\&s\fP type must be insertable in \fIstd::ostreams\fP\&. The (trimmed) width of \fIvalue\fP when inserted into an \fIostream\fP defines the width of the next column, which is right\-aligned\&. As width the previous insertion operator: if a previous definition specified a larger width, then that width is kept\&. Example: .nf // 2 columns, having widths 2 and 5: tab\&.fmt() << 12 << \(dq\&hello\(dq\&; .fi .PP \fBInserting the table\(cq\&s elements\fP .PP In addition to the insertion operator actually inserting a value into the next table\(cq\&s column(s) several format modifying insertion operators are available\&. When a series of specifications are inserted before the actual value is inserted then the specification inserted just before inserting the table\(cq\&s value is used, overruling that column\(cq\&s default specification\&. Format specifications other than those provided by the standard I/O manipulators are ignored when used beyond the table\(cq\&s last column\&. .PP The return types and left\-hand side operands of the following insertion operators use \fBCSVTabIns\fP objects\&. \fBCSVTable\(cq\&s\fP conversion operator \fIoperator CSVTabIns()\fP described below returns a \fBCSVTabIns\fP object which is used by the following insertion operators to insert values into the table\&. .PP .IP o \fBCSVTabIns &operator<<(CSVTabIns &tab, FMT::hline)\fP: .br This operator inserts a horizontal line in the table\(cq\&s next column element\&. It is ignored when used beyond the table\(cq\&s last column; .IP .IP o \fBCSVTabIns &operator<<(CSVTabIns &tab, (*FMT::hline)(unsigned nColumns))\fP: .br This operator inserts a horizontal line spanning the next \fInColumns\fP columns of the table\&. If the argument \fInColumns\fP is omitted then a horizontal line is inserted spanning all of the table\(cq\&s remaining columns\&. When covering multiple columns no separators are used between the columns containing horizontal lines but one continuous horizontal line is used instead\&. The horizontal line is never written beyond the table\(cq\&s last column\&. .IP .IP o \fBCSVTabIns &operator<<(CSVTabIns &tab, Insertable const &value)\fP: .br This operator is defined for the template type \fIInsertable\fP parameter \fIvalue\fP, where \fIvalue\(cq\&s\fP type must be insertable in \fIstd::ostreams\fP\&. The value is inserted into the next table column, using the format specification that\(cq\&s active for that column\&. However, the specifications may be altered just before inserting the value\&. Values inserted beyond the table\(cq\&s last column are inserted as\-is (although standard \fII/O\fP manipulators can still be used); .IP .IP o \fBCSVTabIns &operator<<(CSVTabIns &tab, FMT const &fmt)\fP: .br \fBFMT\fP objects are returned by several free functions defined in the \fIFBB\fP namespace (i\&.e\&., \fBcenter, left,\fP or \fBright\fP, described below in section \fBFREE FUNCTIONS\fP)\&. Example: .nf // left align using precision 2\&. E\&.g\&., // e\&.g\&., \(cq\&12\&.13 \(cq\& tab << left(2) << 12\&.1278; .fi .IP .IP o \fBCSVTabIns &operator<<(CSVTabIns &tab, FMT::Align align)\fP: .br The alignment argument can be \fIFMT::CENTER, FMT::LEFT\fP or \fIFMT::RIGHT\fP\&. Example: .nf // centers \(cq\&12\(cq\& in its column, // e\&.g\&., \(cq\& 12 \(cq\& tab << FMT::CENTER << 12; .fi .IP .IP o \fBvoid operator<<(CSVTabIns &tab, std::ios_base &(*func)(std::ios_base &))\fP: .br This insertion operator accepts manipulators like \fIstd::left\fP and \fIstd::right\fP\&. When inserting these manipulators the next value to insert into the table is manipulated accordingly, overruling the next column\(cq\&s default specification\&. Example: .nf // \(cq\&hi\(cq\& is left\-aligned, using the // using the default width and precision tab << std::left << \(dq\&hi\(dq\&; .fi .IP .IP o \fBCSVTabIns &operator<<(CSVTabIns &tab, Sep const &sep)\fP: .br The separator used when starting to insert values into the table\(cq\&s next row is changed to the separator specified by \fIsep\fP\&. It remains active for the table\(cq\&s current row, also when inserting values beyond the table\(cq\&s last column\&. Example: .nf // writes, e\&.g\&., \(cq\&one, hi there\(cq\& tab << \(dq\&one\(dq\& << FMT::Sep{\(dq\& \(dq\&} << \(dq\&hi\(dq\& << \(dq\&there\(dq\&; .fi .IP .IP o \fBoperator CSVTabIns()\fP: .br The conversion operator returns a \fBCSVTabIns\fP object which is used in combination with the above insertion operators to insert values into the next row of the table\&. Normally insertions start at column 1, but when called after calling \fItab\&.more\fP (see below) then insertions continue after the last element that was inserted into \fBtab\&.more\fP\&. Each time this conversion operator is used another row is added to the table\&. Insertions beyond the table\(cq\&s last column are processed, but \fBCSVTabIns\(cq\&s\fP insertion operators are ignored, inserting values as\-is\&. However, in that case the standard \fIstd::ostream\fP manipulators can also be used\&. .IP .IP o \fBvoid operator()(std::string const &text)\fP: .br Calls \fBtext, 0\fP to insert the trimmed comma\-separated elements of \fItext\fP into the table\(cq\&s next row; .IP .IP o \fBFMT const &operator[](unsigned idx) const\fP: .br Returns the default \fBFMT\fP specification of column \fIidx\fP (see also the description of the member \fBsize()\fP below)\&. .PP .SH "MEMBER FUNCTIONS" .PP In the provided examples \fItab\fP refers to an existing \fBCSVTable\fP object\&. .PP .IP o \fBstd::vector const &columns() const\fP: .br Returns a reference to the vector containing the format specifications of the table managed by \fBCSVTable\fP; .IP .IP o \fBCSVTabDef &fmt(unsigned idx = 0)\fP: .br The elements inserted into the \fBCSVTabDef\fP object returned by \fBfmt()\fP define the specifications of the table\(cq\&s columns\&. Specifications start at column offset \fIidx\fP, using 0 if not specified (its argument may not exceed the number of already defined columns or an exception is thrown)\&. When called repeatedly for already specified columns then the widths of existing columns are kept if they exceed the widths of the corresponding inserted \fBFMT\fP elements\&. Repeated \fBfmt\fP calls may specify more columns than previous calls, in which case new columns are added to the table\&. .IP .IP o \fBvoid fmt(std::string const &colSpecs, unsigned idx = 0)\fP: .br The comma\-separated space\-trimmed words of \fIcolSpecs\fP define the widths of right\-aligned table columns, starting at column index \fIidx\fP, using 0 if not specified (its argument may not exceed the number of already defined columns or an exception is thrown)\&. When called repeatedly for already specified columns then the widths of existing columns are kept if they exceed the lengths of the corresponding trimmed words\&. Repeated calls may specify more columns than previous calls, in which case additional columns are added to the table\&. Example: .nf // Define three right\-aligned columns, // having widths of 3, 3 and 5\&. tab\&.fmt(\(dq\&one, two, three\(dq\&); // add columns 4 thru 6 tab\&.fmt(\(dq\&one, two, three\(dq\&, 3); .fi .IP .IP o \fBunsigned idx() const\fP: .br The index of the column that will be used at the next insertion is returned\&. When inserting more values than the number of defined table columns then the return value of the member \fIsize\fP is returned; .IP .IP o \fBCSVTabIns more(unsigned idx = ~0U)\fP: .br When the default \fIidx\fP argument is used then values that are inserted into the returned \fBCSVTabIns\fP object are inserted beyond the last\-used column of the table\(cq\&s current row (which may be the row\(cq\&s first element)\&. .IP When using another argument then insertions start in column \fIidx\fP\&. If \fIdx\fP exceeds the last\-used column index then intermediate columns remain empty\&. .IP If \fIidx\fP is less than the column index that is used at the next insertion an exception is thrown\&. .IP Insertions beyond the table\(cq\&s last column are processed, but then \fBCSVTabIns\(cq\&s\fP insertion operators are ignored, inserting values as\-is\&. However, in that case the standard \fIstd::ostream\fP manipulators can also be used; .IP Following \fImore\fP the current row doesn\(cq\&t end, but values inserted next are inserted into the same row\&. Example: .nf // a row containing one element: tab << 1; // the next row contains 2 elements: tab\&.more() << 1 << 2; // now containing 4 elements // (element at idx 2 remains empty): tab\&.more(3) << 4; // completes the row, now having // 5 elements: tab << 5; .fi .IP Following \fImore\fP calls the current row ends at the next \fItab\&.row\fP call\&. If following \fImore\fP calls the current row should merely end then simply use \fItab\&.row()\fP; .IP .IP o \fBvoid more(std::string const &text, unsigned idx = ~0U)\fP: .br This member\(cq\&s \fIidx\fP parameter is handled as described at the previous member\&. .IP The trimmed comma\-separated elements of \fItext\fP are inserted into the current row, without ending the current row; .IP .IP o \fBCSVTabIns row(unsigned idx = ~0U)\fP: .br This member\(cq\&s \fIidx\fP parameter and insertions into the returned \fBCSVTabIns\fP object are handled as described at the first \fImore\fP member, but the current row ends at the end of the statement\&. Example: .nf // a row containing one element: tab << 1; // the next row contains 2 elements: tab\&.more() << 1 << 2; // the now contains 4 elements // (element at idx 2 remains empty): tab\&.row(3) << 4; .fi .IP .IP o \fBvoid row(std::string const &text, unsigned idx = ~0U)\fP: .br This member\(cq\&s \fIidx\fP parameter is handled as described at the first \fImore\fP member\&. .IP The trimmed comma\-separated elements of \fItext\fP are inserted into the current row, whereafter the row ends; .IP .IP o \fBvoid stream(std::ostream &out)\fP: .br After calling \fItab\&.stream(out)\fP the table\(cq\&s construction continues at the next row using the stream \fIout\fP; .IP .IP o \fBvoid stream(std::ofstream &&tmp)\fP: .br After calling this member the table\(cq\&s construction continues at the next row using the \fIofstream tmp\fP, whih is grabbed by \fICSVTable\fP; .IP .IP o \fBvoid stream(std::string const &fname, std::ios::openmode mode = std::ios::out)\fP: .br After calling this member the table\(cq\&s construction continues at the next row using the (path)name \fIfname\fP, by default (re)writing the file\&. If the file already exists and \fICSVTable\fP should start writing at the file\(cq\&s end use, e\&.g\&., \fIios::ate | ios::in\fP\&. An exception is thrown if the specified file cannot be opened; .IP .IP o \fBstd::ostream &stream()\fP: .br A reference to the currently used stream is returned; .IP .IP o \fBstd::string const &sep() const\fP: .br Returns the currently used default column separator; .IP .IP o \fBvoid sep(std::string const &separator)\fP: .br Changes the currently used default column separator to \fIseparator\fP\&. .IP .IP o \fBunsigned size() const\fP: .br The number of defined columns is returned; .IP .SH "FREE FUNCTIONS" .PP In the following examples \fItab\&.fmt()\fP refers to a \fBCSVTabDef\fP object\&. .PP next examples \fItab\fP refers to a \fBCSVTable\fP object (using its conversion to a \fBCSVTabIns\fP object) and .PP \fBDefining Column Characteristics\fP .PP The following functions are used to specify the alignment, width and optional precision of columns\&. The first argument of these functions specifies the column\(cq\&s width, the second argument is optional and specifies the column\(cq\&s precision (used when inserting floating point values)\&. The precision is only used if its value is less than the column\(cq\&s width\&. .PP .IP o \fBFMT center(unsigned width, unsigned precision = ~0U)\fP: .br When inserting this function\(cq\&s return value into \fItab\&.fmt()\fP the values inserted into its column are centered in fields of \fIwidth\fP characters wide\&. Example: .nf // values are centered in fields of 10 // characters wide, floating point values // use 3 digit behind the decimal point: tab\&.fmt() << center(10, 3); .fi .IP .IP o \fBFMT center(std::string const &str, unsigned precision = ~0U)\fP: .br A convenience function calling \fI str\&.length(), precision \fP; .IP .IP o \fBFMT left(unsigned width, unsigned precision = ~0U)\fP: .br When inserting this function\(cq\&s return value into \fItab\&.fmt()\fP the values inserted into its column are left\-aligned in fields of \fIwidth\fP characters wide\&. Example: .nf // values are left\-aligned in fields // of 5 characters wide\&. tab\&.fmt() << left(5); .fi .IP o \fBFMT left(std::string const &str, unsigned precision = ~0U)\fP: .br A convenience function calling \fIleft(str\&.length(), precision)\fP; .IP .IP o \fBFMT right(unsigned width, unsigned precision = ~0U)\fP: .br When inserting this function\(cq\&s return value into \fItab\&.fmt()\fP the values inserted into its column are right\-aligned in fields of \fIwidth\fP characters wide\&. Example: .nf // values are right\-aligned in fields // of 5 characters wide\&. tab\&.fmt() << right(5); .fi Right\-alignment is also used when using \fBCSVTab\(cq\&s fmt(std::string)\fP member or when directly inserting values into \fBCSVTabDef\fP objects\&. .IP .IP o \fBFMT right(std::string const &str, unsigned precision = ~0U)\fP: .br A convenience function calling \fIright(str\&.length(), precision)\fP; .PP \fBInserting Table Elements\fP .PP In the following examples \fItab\fP refers to a \fBCSVTable\fP object returning a \fBCSVTabIns\fP object using its conversion operator\&. .PP Except for the function \fIhline\fP the following functions are used to alter the column\(cq\&s default alignment and precision\&. The precision is only used if its value is less than the column\(cq\&s width\&. By specifying \fI~0U\fP the precision is ignored\&. If only the default alignment should be overruled then inserting the corresponding \fIFMT::Align\fP value suffices\&. .PP Altering the default alignment of individual columns: .PP .IP o \fBFMT precision \fP: .br After inserting this function\(cq\&s return value into \fItab\fP the value inserted next is centered, using \fIprecision\fP when inserting floating point values\&. .nf // centers 9\&.87 in column 1 tab << center(2) << 9\&.876\(dq\&; .fi .IP .IP o \fBFMT left(precision)\fP: .br After inserting this function\(cq\&s return value into \fItab\fP the value inserted next is left\-aligned, using \fIprecision\fP when inserting floating point values\&. .nf // left\-aligns 9\&.87 in column 1 tab << left(2) << 9\&.876\(dq\&; .fi .IP .IP o \fBFMT right(precision)\fP: .br When inserting this function\(cq\&s return value into \fItab\fP the value inserted next is right\-aligned, using \fIprecision\fP when inserting floating point values\&. .nf // right\-aligns 9\&.87 in column 1 tab << right(2) << 9\&.876\(dq\&; .fi By default \fBCSVTable\fP uses right\-alignment\&. .PP Joining columns: .PP Alignments specifications may span multiple columns\&. This is realized through the \fIjoin\fP functions\&. When inserting a value after inserting the return value of a \fIjoin\fP member then that value is inserted occupying all the columns and using the alignment type specified when calling \fIjoin\fP\&. If necessary the number of columns is reduced to avoid exceeding the table\(cq\&s last column\&. .PP .IP o \fBFMT join(unsigned nCols, FMT::Align align, unsigned precision = ~0U)\fP: .br A value that\(cq\&s inserted into the table after inserting \fIjoin\(cq\&s\fP return value occupies \fInCols\fP columns, using alignment type \fIalign\fP, and optionally using \fIprecision\fP when inserting floating point values\&. The alignment specification must be \fIFMT::CENTER, FMT::LEFT\fP or \fIFMT::RIGHT\fP\&. Example: .nf // writes (assuming columns 2 and 3 occupy // 10 characters): // left, mid , right tab << \(dq\&left\(dq\& << join(2, FMT::CENTER) << \(dq\&mid\(dq\& << \(dq\&right\(dq\&\(dq\&; .fi .IP .IP o \fBFMT join(FMT::Align align, unsigned precision = ~0U)\fP: .br Same effect as the previous \fIjoin\fP function, but this function occupies all remaining columns of the table\(cq\&s current row (this can also be accomplished by calling the first \fIjoin\fP function specifying \fI~0U\fP as its first argument)\&. .PP Inserting horizontal lines: .PP If a single table element should contain a horizontal line then simply inserting \fIAlign::HLINE\fP works fine\&. The \fIhline\fP functions are used to insert horizontal lines spanning one or more table columns\&. .PP .IP o \fBFMT hline(unsigned nCols = ~0U)\fP: .br When inserting this function\(cq\&s return value into a \fBCSVTabIns\fP object a horizontal line spanning \fInCols\fP columns is inserted into the table\&. If necessary \fInCols\fP is reduced so that the horizontal line does not exceed the table\(cq\&s last column\&. When spanning multiple columns no column separated are used between the spanned columns: a single uninterrupted horizontal line is inserted\&. Example: .nf // columns 1 and 2: a horizontal line, column 3: // contains \(cq\&hi\(cq\& (preceded by the column separator) tab << hline(2) << \(dq\&hi\(dq\&; .fi .PP .SH "EXAMPLE" .nf #include using namespace FBB; int main() { CSVTable tab; tab\&.fmt() << \(dq\&case\(dq\& << right(\(dq\&length\(dq\&, 2) << right(\(dq\&weight\(dq\&, 1) << right(\(dq\&length\(dq\&, 2) << right(\(dq\&weight\(dq\&, 1); tab\&.sep(\(dq\& \(dq\&); tab << hline(); tab << \(dq\&\(dq\& << join(4, FMT::CENTER) << \(dq\&Gender\(dq\&; tab << \(dq\&\(dq\& << hline(); tab << \(dq\&\(dq\& << join(2, FMT::CENTER) << \(dq\&Female\(dq\& << join(2, FMT::CENTER) << \(dq\&Male\(dq\&; tab << \(dq\&\(dq\& << hline(2) << hline(2); tab << \(dq\&Case\(dq\& << \(dq\&Length\(dq\& << \(dq\&Weight\(dq\& << \(dq\&Length\(dq\& << \(dq\&Weight\(dq\&; tab << hline(); tab << 1 << 1\&.744 << 55\&.345 << 1\&.7244 << 64\&.801; tab << 2 << 1\&.58 << 57\&.545 << 1\&.8174 << 81\&.451; tab << 3 << 1\&.674 << 62\&.125 << 1\&.8244 << 80\&.201; tab << hline(); } .fi .PP This program writes the following table to \fIstd::cout\fP: .nf \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- Gender \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- Female Male \-\-\-\-\-\-\-\-\-\-\-\-\-\- \-\-\-\-\-\-\-\-\-\-\-\-\-\- Case Length Weight Length Weight \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- 1 1\&.74 55\&.3 1\&.72 64\&.8 2 1\&.58 57\&.5 1\&.82 81\&.5 3 1\&.67 62\&.1 1\&.82 80\&.2 \-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\-\- .fi .PP .SH "FILES" \fIbobcat/csvtable\fP \- defines the class interface .PP .SH "SEE ALSO" \fBbobcat\fP(7), \fBtable\fP(3bobcat) .PP .SH "BUGS" None Reported\&. .PP .SH "BOBCAT PROJECT FILES" .PP .IP o \fIhttps://fbb\-git\&.gitlab\&.io/bobcat/\fP: gitlab project page; .IP o \fIbobcat_5\&.07\&.00\-x\&.dsc\fP: detached signature; .IP o \fIbobcat_5\&.07\&.00\-x\&.tar\&.gz\fP: source archive; .IP o \fIbobcat_5\&.07\&.00\-x_i386\&.changes\fP: change log; .IP o \fIlibbobcat1_5\&.07\&.00\-x_*\&.deb\fP: debian package containing the libraries; .IP o \fIlibbobcat1\-dev_5\&.07\&.00\-x_*\&.deb\fP: debian package containing the libraries, headers and manual pages; .PP .SH "BOBCAT" Bobcat is an acronym of `Brokken\(cq\&s Own Base Classes And Templates\(cq\&\&. .PP .SH "COPYRIGHT" This is free software, distributed under the terms of the GNU General Public License (GPL)\&. .PP .SH "AUTHOR" Frank B\&. Brokken (\fBf\&.b\&.brokken@rug\&.nl\fP)\&. .PP