I've never been satisfied with any of the possible sprintf()
-like functions in C++:
sprintf()
is a C function and it's very unsafe and dangerous to use (undefined behavior all over the place)boost::format
is too slow and awkward to use (think of the%
syntax)iostream
is extremely awkward to use
So I came up with my own. Those are my requirements:
- Inspired by C#'s format function
- Must never fail at run time, never crash and never have undefined behavior, no matter what you call it with. Should fail at compile time whenever possible instead.
- Must be expandable (if you create a class
Person
, then you can pass aPerson
object to the function) - Must be fast
- The format string must be easy to localize
- The format string must not have placeholders whose syntax depends on the argument type (ie, no
%s
vs%d
) - Must have a fairly "normal" syntax (no % like boost::format)
I'm interested in reviews on the satisfaction of the requirements above. I'm especially interested in reviews from the end-user perspective and less about the internals of the code (i.e., the code that is hidden from the end user).
A few examples:
// Returns a string containing "Hello my name is Andreas and I'm 22 years old".
Format("Hello my name is {0} and I'm {1} years old.", "Andreas", 22);
// Returns "Hex: 0xA"
Format("Hex: {0:x}", 10);
// Fails to compile: Person is not a built in type and doesn't have any function to convert to string
struct Person {};
Person p;
Format("Person: {0}", p);
// "Person: Andreas Bonini" [Note: if it was {0:abc}, then Person::ToString("abc") would have been called]
struct Person {
Person(string first, string last) : First(first), Last(last) {}
string ToString(const string &options) const { return Format("{0} {1}", First, Last); }
string First, Last;
};
Person p("Andreas", "Bonini");
Format("Person: {0}", p);
These are my unit tests:
TEST(Format)
{
CHECK_EQUAL(Format("Testing {0} test {0}{0} test", 123), "Testing 123 test 123123 test");
CHECK_EQUAL(Format("{0}", (const char *)NULL), "{null}");
CHECK_EQUAL(Format("Test double {0} - {1}", 0, 1), "Test double 0 - 1");
CHECK_EQUAL(Format("Test options: {0:x}", 0xABC), "Test options: 0xABC");
CHECK_EQUAL(Format("Test malformed: {0:x", 0xABC), "Test malformed: {0:x");
CHECK_EQUAL(Format("Check stupid: {0:bmkldmbkglmbgk902 r iko4om wkl lfs s,gf, gfsdg fsd ! @ G}", "stupid"), "Check stupid: stupid");
CHECK_EQUAL(Format("Check missing: {1}", 0), "Check missing: {Argument 1}");
CHECK_EQUAL(Format("Master format test {0} {1} {2 {2:2} {3} {4:e} {5:x} {0}", 0, 1234.55566f, 1.11111f, "lolz", "a'b", 0xABCDEFABCDEFULL),
"Master format test 0 1234.56 {2 1.11 lolz 'a\\'b' 0xABCDEFABCDEF 0");
CHECK_EQUAL(Format("{0:x}", 0xFFFFFFFF), "0xFFFFFFFF");
}
Note that due to C++ limitations (lack of variadic templates) the code isn't exactly pretty. Also the code is part of a bigger library so it won't compile of its own.
/****************************************************************************************
* Prism
* File Name: Format.h
* Added on: 2010/09/26 14:09:52
*/
/***************************************************************************************/
#pragma once
#include <boost/type_traits.hpp>
/***************************************************************************************/
/* This is the main formatting function; it is 100% type safe and hopefully fast. It's inspired
* by C#'s String.Format() function and has pretty much the base syntax:
*
* string format = Format("Hello {0}, my name is {1}.", "you", "me");
*
* More precisely the placeholder can be:
* {n[,a][:o]}
*
* n = Number of argument, starting from 0
* a = Alignment; if it's positive it is right aligned, otherwise left aligned
* o = Options
*
* The arguments themselves to the conversion and handle the options. For each passed argument the
* .ToString(options) function will be called, and the returned value will be used for replacing the
* placeholder.
*
* Of course this won't work with built in types such as int. The conversion for those is implemented
* in the library, which supports the following types (and options).
*
* The 'a' option means alternative.
*
* -- bool --
* - No options: prints "true" or "false".
* - a: prints "yes" or "no".
*
* -- char --
* - No options: prints the character normally
* - a: prints the character as a number.
*
* -- short, int, long --
* - No options: prints the number normally
* - b: prints the number as binary
* - x: prints the number as hex, prepending "0x"
* - X: prints the number as hex, without "0x"
* - ,: prints the number with a comma as thousands separator
*
* -- float, double --
* - No options: prints the number normally
* - A number (N): equivalent to %.Nf
* - %: multiplies by 100, adds a % sign
*
* -- string --
* - No options: prints the string normally
* - e: Escapes the string for use in MySQL queries.
*
* >>> Error handling <<<
* - Not enough arguments: FATAL() is called
* - Too many arguments: not an error; extra arguments are ignored
* - Unknown options: not an error; unknown options may not be implemented yet
*/
/***************************************************************************************/
namespace Prism
{
namespace Text
{
namespace Conversion
{
template<class T>
string IntToString(T _val, bool hasSign, const string &options)
{
typename boost::make_signed<T>::type valSigned = _val;
typename boost::make_unsigned<T>::type valUnsigned = _val;
if(options == ",")
return GetCommaNumber(hasSign ? valSigned : valUnsigned);
static const char itoa_tab[10] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' };
static const char xtoa_tab[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
static const char btoa_tab[2] = { '0', '1' };
int base;
string ret;
const char *tab;
char tmp[128];
char *ptr = &tmp[sizeof(tmp) - 1];
*ptr = 0;
/* Parse options, set up variables */
if (options == "b") {
base = 2;
ret.reserve(64 + 1);
hasSign = false;
tab = btoa_tab;
} else if (options == "x") {
base = 16;
ret.reserve(16 + 2 + 1);
ret.push_back('0');
ret.push_back('x');
hasSign = false;
tab = xtoa_tab;
} else if (options == "X") {
base = 16;
ret.reserve(16 + 2);
hasSign = false;
tab = xtoa_tab;
} else {
base = 10;
ret.reserve(22);
tab = itoa_tab;
}
/* If it's negative */
if(hasSign && valSigned < 0)
{
ret.push_back('-');
valSigned = Math::Abs(valSigned);
valUnsigned = valSigned;
}
do {
*--ptr = tab[valUnsigned % base];
valUnsigned /= base;
} while (valUnsigned);
while(*ptr)
ret.push_back(*ptr++);
return ret;
}
inline string ToString(const char *s, const string &options)
{
if(!s)
s = "{null}";
if(options == "e")
return SqlSafeCopy(s);
return s;
}
inline string ToString(char *s, const string &options)
{
return ToString((const char *)s, options);
}
template<typename T>
string ToString(const T &val, const string &options) { return val.ToString(options); }
template<> string ToString(const char &val, const string &options);
template<> string ToString(const bool &val, const string &options);
template<> string ToString(const float &val, const string &options);
template<> string ToString(const double &val, const string &options);
template<> inline string ToString(const int64 &val, const string &options) { return IntToString(val, true, options); }
template<> inline string ToString(const uint64 &val, const string &options) { return IntToString(val, false, options); }
template<> inline string ToString(const int32 &val, const string &options) { return IntToString(val, true, options); }
template<> inline string ToString(const uint32 &val, const string &options) { return IntToString(val, false, options); }
template<> inline string ToString(const int16 &val, const string &options) { return IntToString(val, true, options); }
template<> inline string ToString(const uint16 &val, const string &options) { return IntToString(val, false, options); }
template<> inline string ToString(const float &val, const string &options) { return ToString(static_cast<double>(val), options); }
template<> inline string ToString(const string &s, const string &options)
{
if(options == "e")
return SqlSafeCopy(s);
return s;
}
}
}
}
/***************************************************************************************/
namespace Prism
{
namespace Text
{
struct PlaceholderData
{
PlaceholderData(int start, int end, const string &argument, int &final_length) : Start(start), End(end), Argument(argument)
{
final_length = final_length - (End - Start) + Argument.length();
}
int Start;
int End;
string Argument;
};
extern string _FinalizeFormat(const string &str, const vector<PlaceholderData> &placeholders, int final_length);
extern bool _FindPlaceholder(const char *str, int &start, const int &end, int &num, int &placeholder_length, string &options);
#include "FormatNoVariadicTemplates.h"
}
}
/***************************************************************************************/
/****************************************************************************************
* Prism
* File Name: Format.cpp
* Added on: 2010/09/26 14:56:35
*/
/***************************************************************************************/
#include "Prism.h"
#include "Format.h"
#include "Text.h"
#if COMPILER == COMPILER_MSVC
#pragma warning (disable: 4996)
#endif
namespace Prism
{
namespace Text
{
/***************************************************************************************/
namespace Conversion
{
template<>
string ToString(const char &val, const string &options)
{
const bool alternative = (options == "a");
if (!alternative)
return string(1, val);
else
return ToString((int)val, "");
}
template<>
string ToString(const bool &val, const string &options)
{
static const char *normalStrings[] = { "true", "false" };
static const char *alternativeStrings[] = { "yes", "no" };
const bool alternative = (options == "a");
const char **strings = alternative ? alternativeStrings : normalStrings;
if (val)
return strings[0];
else
return strings[1];
}
template<>
string ToString(const double &val, const string &options)
{
if (options[0] == '%')
return ToString(val * 100, options.substr(1)) + "%";
char ret[128];
if (IsDigit(options[0]) && !options[1]) {
char format[5];
format[0] = '%';
format[1] = '.';
format[2] = options[0];
format[3] = 'f';
format[4] = '\0';
sprintf(ret, format, val);
} else
sprintf(ret, "%g", val);
return ret;
}
}
/***************************************************************************************/
string _FinalizeFormat(const string &str, const vector<PlaceholderData> &placeholders, int final_length)
{
if(placeholders.empty())
return str;
string ret;
ret.reserve(final_length);
int current_position = 0;
const char *ptr = str.data();
foreach (const PlaceholderData &placeholder, placeholders) {
if (placeholder.Start != current_position) {
const int bytes = (placeholder.Start - current_position);
ret.append(ptr + current_position, bytes);
current_position += bytes;
}
ret.append(placeholder.Argument);
current_position += (placeholder.End - placeholder.Start);
}
const int remaining_bytes = str.size() - current_position;
if (remaining_bytes > 0)
ret.append(ptr + current_position, remaining_bytes);
return ret;
}
/***************************************************************************************/
static bool ReadPlaceholder(const char *str, int &start, const int &end, int &num, int &placeholder_length, string &options)
{
const char *placeholder_number = &str[start + 1];
char *endStr;
if (!IsDigit(*placeholder_number))
return false;
num = strtoul(placeholder_number, &endStr, 10);
if (!endStr)
return false;
if (*endStr == ':') {
/* Read options */
++endStr;
const char *begin = endStr;
while (endStr < &str[end] && *endStr != '}')
++endStr;
if (endStr == &str[end])
return false;
options.assign(begin, endStr - begin);
} else
options = "";
if (*endStr != '}')
return false;
++endStr;
placeholder_length = endStr - &str[start];
return true;
}
/***************************************************************************************/
bool _FindPlaceholder(const char *str, int &start, const int &end, int &num, int &placeholder_length, string &options)
{
/* Find the '{' */
for (int i = start; i < end; ++i)
{
if (str[i] != '{')
continue;
/* Check if there is enough space for the minimum spaceholder length, 3: {.} */
if (end - i < 3)
continue;
if (ReadPlaceholder(str, i, end, num, placeholder_length, options))
{
start = i;
return true;
}
}
/* If we reach here, we reached the end of the string */
start = end;
return false;
}
/***************************************************************************************/
}
}
/****************************************************************************************
* Prism
* File Name: FormatNoVariadicTemplates.h
* Added on: 2010/09/26 21:04:33
*/
/***************************************************************************************/
#pragma once
/***************************************************************************************/
/* Here we go.. */
#define FNVT_BEGIN vector<PlaceholderData> placeholders; \
int final_length = str.length(); \
int start = 0; \
const int end = str.length(); \
int num, placeholder_length; \
string argument, options; \
while (start < end) { \
if (!_FindPlaceholder(str.c_str(), start, end, num, placeholder_length, options)) \
continue; \
switch(num) {
#define FNVT_END default: \
argument = Format("{Argument {0}}", num); \
break; \
} \
placeholders.push_back(PlaceholderData(start, start + placeholder_length, argument, final_length)); \
start += placeholder_length; \
} \
return _FinalizeFormat(str, placeholders, final_length);
#define ARGUMENT(n) case n: \
argument = Conversion::ToString(_ ## n, options); \
break; \
/***************************************************************************************/
template<typename A>
string Format(const string &str, const A &_0)
{
FNVT_BEGIN;
ARGUMENT(0);
FNVT_END;
}
template<typename A, typename B>
string Format(const string &str, const A &_0, const B &_1)
{
FNVT_BEGIN;
ARGUMENT(0);
ARGUMENT(1);
FNVT_END;
}
template<typename A, typename B, typename C>
string Format(const string &str, const A &_0, const B &_1, const C &_2)
{
FNVT_BEGIN;
ARGUMENT(0);
ARGUMENT(1);
ARGUMENT(2);
FNVT_END;
}
template<typename A, typename B, typename C, typename D>
string Format(const string &str, const A &_0, const B &_1, const C &_2, const D &_3)
{
FNVT_BEGIN;
ARGUMENT(0);
ARGUMENT(1);
ARGUMENT(2);
ARGUMENT(3);
FNVT_END;
}
template<typename A, typename B, typename C, typename D, typename E>
string Format(const string &str, const A &_0, const B &_1, const C &_2, const D &_3, const E &_4)
{
FNVT_BEGIN;
ARGUMENT(0);
ARGUMENT(1);
ARGUMENT(2);
ARGUMENT(3);
ARGUMENT(4);
FNVT_END;
}
template<typename A, typename B, typename C, typename D, typename E, typename F>
string Format(const string &str, const A &_0, const B &_1, const C &_2, const D &_3, const E &_4, const F &_5)
{
FNVT_BEGIN;
ARGUMENT(0);
ARGUMENT(1);
ARGUMENT(2);
ARGUMENT(3);
ARGUMENT(4);
ARGUMENT(5);
FNVT_END;
}
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G>
string Format(const string &str, const A &_0, const B &_1, const C &_2, const D &_3, const E &_4, const F &_5, const G &_6)
{
FNVT_BEGIN;
ARGUMENT(0);
ARGUMENT(1);
ARGUMENT(2);
ARGUMENT(3);
ARGUMENT(4);
ARGUMENT(5);
ARGUMENT(6);
FNVT_END;
}
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H>
string Format(const string &str, const A &_0, const B &_1, const C &_2, const D &_3, const E &_4, const F &_5, const G &_6, const H &_7)
{
FNVT_BEGIN;
ARGUMENT(0);
ARGUMENT(1);
ARGUMENT(2);
ARGUMENT(3);
ARGUMENT(4);
ARGUMENT(5);
ARGUMENT(6);
ARGUMENT(7);
FNVT_END;
}
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I>
string Format(const string &str, const A &_0, const B &_1, const C &_2, const D &_3, const E &_4, const F &_5, const G &_6, const H &_7, const I &_8)
{
FNVT_BEGIN;
ARGUMENT(0);
ARGUMENT(1);
ARGUMENT(2);
ARGUMENT(3);
ARGUMENT(4);
ARGUMENT(5);
ARGUMENT(6);
ARGUMENT(7);
ARGUMENT(8);
FNVT_END;
}
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J>
string Format(const string &str, const A &_0, const B &_1, const C &_2, const D &_3, const E &_4, const F &_5, const G &_6, const H &_7, const I &_8, const J &_9)
{
FNVT_BEGIN;
ARGUMENT(0);
ARGUMENT(1);
ARGUMENT(2);
ARGUMENT(3);
ARGUMENT(4);
ARGUMENT(5);
ARGUMENT(6);
ARGUMENT(7);
ARGUMENT(8);
ARGUMENT(9);
FNVT_END;
}
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K>
string Format(const string &str, const A &_0, const B &_1, const C &_2, const D &_3, const E &_4, const F &_5, const G &_6, const H &_7, const I &_8, const J &_9, const K &_10)
{
FNVT_BEGIN;
ARGUMENT(0);
ARGUMENT(1);
ARGUMENT(2);
ARGUMENT(3);
ARGUMENT(4);
ARGUMENT(5);
ARGUMENT(6);
ARGUMENT(7);
ARGUMENT(8);
ARGUMENT(9);
ARGUMENT(10);
FNVT_END;
}
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K, typename L>
string Format(const string &str, const A &_0, const B &_1, const C &_2, const D &_3, const E &_4, const F &_5, const G &_6, const H &_7, const I &_8, const J &_9, const K &_10, const L &_11)
{
FNVT_BEGIN;
ARGUMENT(0);
ARGUMENT(1);
ARGUMENT(2);
ARGUMENT(3);
ARGUMENT(4);
ARGUMENT(5);
ARGUMENT(6);
ARGUMENT(7);
ARGUMENT(8);
ARGUMENT(9);
ARGUMENT(10);
ARGUMENT(11);
FNVT_END;
}
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K, typename L, typename M>
string Format(const string &str, const A &_0, const B &_1, const C &_2, const D &_3, const E &_4, const F &_5, const G &_6, const H &_7, const I &_8, const J &_9, const K &_10, const L &_11, const M &_12)
{
FNVT_BEGIN;
ARGUMENT(0);
ARGUMENT(1);
ARGUMENT(2);
ARGUMENT(3);
ARGUMENT(4);
ARGUMENT(5);
ARGUMENT(6);
ARGUMENT(7);
ARGUMENT(8);
ARGUMENT(9);
ARGUMENT(10);
ARGUMENT(11);
ARGUMENT(12);
FNVT_END;
}
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K, typename L, typename M, typename N>
string Format(const string &str, const A &_0, const B &_1, const C &_2, const D &_3, const E &_4, const F &_5, const G &_6, const H &_7, const I &_8, const J &_9, const K &_10, const L &_11, const M &_12, const N &_13)
{
FNVT_BEGIN;
ARGUMENT(0);
ARGUMENT(1);
ARGUMENT(2);
ARGUMENT(3);
ARGUMENT(4);
ARGUMENT(5);
ARGUMENT(6);
ARGUMENT(7);
ARGUMENT(8);
ARGUMENT(9);
ARGUMENT(10);
ARGUMENT(11);
ARGUMENT(12);
ARGUMENT(13);
FNVT_END;
}
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K, typename L, typename M, typename N, typename O>
string Format(const string &str, const A &_0, const B &_1, const C &_2, const D &_3, const E &_4, const F &_5, const G &_6, const H &_7, const I &_8, const J &_9, const K &_10, const L &_11, const M &_12, const N &_13, const O &_14)
{
FNVT_BEGIN;
ARGUMENT(0);
ARGUMENT(1);
ARGUMENT(2);
ARGUMENT(3);
ARGUMENT(4);
ARGUMENT(5);
ARGUMENT(6);
ARGUMENT(7);
ARGUMENT(8);
ARGUMENT(9);
ARGUMENT(10);
ARGUMENT(11);
ARGUMENT(12);
ARGUMENT(13);
ARGUMENT(14);
FNVT_END;
}
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K, typename L, typename M, typename N, typename O, typename P>
string Format(const string &str, const A &_0, const B &_1, const C &_2, const D &_3, const E &_4, const F &_5, const G &_6, const H &_7, const I &_8, const J &_9, const K &_10, const L &_11, const M &_12, const N &_13, const O &_14, const P &_15)
{
FNVT_BEGIN;
ARGUMENT(0);
ARGUMENT(1);
ARGUMENT(2);
ARGUMENT(3);
ARGUMENT(4);
ARGUMENT(5);
ARGUMENT(6);
ARGUMENT(7);
ARGUMENT(8);
ARGUMENT(9);
ARGUMENT(10);
ARGUMENT(11);
ARGUMENT(12);
ARGUMENT(13);
ARGUMENT(14);
ARGUMENT(15);
FNVT_END;
}
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K, typename L, typename M, typename N, typename O, typename P, typename Q>
string Format(const string &str, const A &_0, const B &_1, const C &_2, const D &_3, const E &_4, const F &_5, const G &_6, const H &_7, const I &_8, const J &_9, const K &_10, const L &_11, const M &_12, const N &_13, const O &_14, const P &_15, const Q &_16)
{
FNVT_BEGIN;
ARGUMENT(0);
ARGUMENT(1);
ARGUMENT(2);
ARGUMENT(3);
ARGUMENT(4);
ARGUMENT(5);
ARGUMENT(6);
ARGUMENT(7);
ARGUMENT(8);
ARGUMENT(9);
ARGUMENT(10);
ARGUMENT(11);
ARGUMENT(12);
ARGUMENT(13);
ARGUMENT(14);
ARGUMENT(15);
ARGUMENT(16);
FNVT_END;
}
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K, typename L, typename M, typename N, typename O, typename P, typename Q, typename R>
string Format(const string &str, const A &_0, const B &_1, const C &_2, const D &_3, const E &_4, const F &_5, const G &_6, const H &_7, const I &_8, const J &_9, const K &_10, const L &_11, const M &_12, const N &_13, const O &_14, const P &_15, const Q &_16, const R &_17)
{
FNVT_BEGIN;
ARGUMENT(0);
ARGUMENT(1);
ARGUMENT(2);
ARGUMENT(3);
ARGUMENT(4);
ARGUMENT(5);
ARGUMENT(6);
ARGUMENT(7);
ARGUMENT(8);
ARGUMENT(9);
ARGUMENT(10);
ARGUMENT(11);
ARGUMENT(12);
ARGUMENT(13);
ARGUMENT(14);
ARGUMENT(15);
ARGUMENT(16);
ARGUMENT(17);
FNVT_END;
}
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K, typename L, typename M, typename N, typename O, typename P, typename Q, typename R, typename S>
string Format(const string &str, const A &_0, const B &_1, const C &_2, const D &_3, const E &_4, const F &_5, const G &_6, const H &_7, const I &_8, const J &_9, const K &_10, const L &_11, const M &_12, const N &_13, const O &_14, const P &_15, const Q &_16, const R &_17, const S &_18)
{
FNVT_BEGIN;
ARGUMENT(0);
ARGUMENT(1);
ARGUMENT(2);
ARGUMENT(3);
ARGUMENT(4);
ARGUMENT(5);
ARGUMENT(6);
ARGUMENT(7);
ARGUMENT(8);
ARGUMENT(9);
ARGUMENT(10);
ARGUMENT(11);
ARGUMENT(12);
ARGUMENT(13);
ARGUMENT(14);
ARGUMENT(15);
ARGUMENT(16);
ARGUMENT(17);
ARGUMENT(18);
FNVT_END;
}
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K, typename L, typename M, typename N, typename O, typename P, typename Q, typename R, typename S, typename T>
string Format(const string &str, const A &_0, const B &_1, const C &_2, const D &_3, const E &_4, const F &_5, const G &_6, const H &_7, const I &_8, const J &_9, const K &_10, const L &_11, const M &_12, const N &_13, const O &_14, const P &_15, const Q &_16, const R &_17, const S &_18, const T &_19)
{
FNVT_BEGIN;
ARGUMENT(0);
ARGUMENT(1);
ARGUMENT(2);
ARGUMENT(3);
ARGUMENT(4);
ARGUMENT(5);
ARGUMENT(6);
ARGUMENT(7);
ARGUMENT(8);
ARGUMENT(9);
ARGUMENT(10);
ARGUMENT(11);
ARGUMENT(12);
ARGUMENT(13);
ARGUMENT(14);
ARGUMENT(15);
ARGUMENT(16);
ARGUMENT(17);
ARGUMENT(18);
ARGUMENT(19);
FNVT_END;
}
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K, typename L, typename M, typename N, typename O, typename P, typename Q, typename R, typename S, typename T, typename U>
string Format(const string &str, const A &_0, const B &_1, const C &_2, const D &_3, const E &_4, const F &_5, const G &_6, const H &_7, const I &_8, const J &_9, const K &_10, const L &_11, const M &_12, const N &_13, const O &_14, const P &_15, const Q &_16, const R &_17, const S &_18, const T &_19, const U &_20)
{
FNVT_BEGIN;
ARGUMENT(0);
ARGUMENT(1);
ARGUMENT(2);
ARGUMENT(3);
ARGUMENT(4);
ARGUMENT(5);
ARGUMENT(6);
ARGUMENT(7);
ARGUMENT(8);
ARGUMENT(9);
ARGUMENT(10);
ARGUMENT(11);
ARGUMENT(12);
ARGUMENT(13);
ARGUMENT(14);
ARGUMENT(15);
ARGUMENT(16);
ARGUMENT(17);
ARGUMENT(18);
ARGUMENT(19);
ARGUMENT(20);
FNVT_END;
}
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K, typename L, typename M, typename N, typename O, typename P, typename Q, typename R, typename S, typename T, typename U, typename V>
string Format(const string &str, const A &_0, const B &_1, const C &_2, const D &_3, const E &_4, const F &_5, const G &_6, const H &_7, const I &_8, const J &_9, const K &_10, const L &_11, const M &_12, const N &_13, const O &_14, const P &_15, const Q &_16, const R &_17, const S &_18, const T &_19, const U &_20, const V &_21)
{
FNVT_BEGIN;
ARGUMENT(0);
ARGUMENT(1);
ARGUMENT(2);
ARGUMENT(3);
ARGUMENT(4);
ARGUMENT(5);
ARGUMENT(6);
ARGUMENT(7);
ARGUMENT(8);
ARGUMENT(9);
ARGUMENT(10);
ARGUMENT(11);
ARGUMENT(12);
ARGUMENT(13);
ARGUMENT(14);
ARGUMENT(15);
ARGUMENT(16);
ARGUMENT(17);
ARGUMENT(18);
ARGUMENT(19);
ARGUMENT(20);
ARGUMENT(21);
FNVT_END;
}
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K, typename L, typename M, typename N, typename O, typename P, typename Q, typename R, typename S, typename T, typename U, typename V, typename W>
string Format(const string &str, const A &_0, const B &_1, const C &_2, const D &_3, const E &_4, const F &_5, const G &_6, const H &_7, const I &_8, const J &_9, const K &_10, const L &_11, const M &_12, const N &_13, const O &_14, const P &_15, const Q &_16, const R &_17, const S &_18, const T &_19, const U &_20, const V &_21, const W &_22)
{
FNVT_BEGIN;
ARGUMENT(0);
ARGUMENT(1);
ARGUMENT(2);
ARGUMENT(3);
ARGUMENT(4);
ARGUMENT(5);
ARGUMENT(6);
ARGUMENT(7);
ARGUMENT(8);
ARGUMENT(9);
ARGUMENT(10);
ARGUMENT(11);
ARGUMENT(12);
ARGUMENT(13);
ARGUMENT(14);
ARGUMENT(15);
ARGUMENT(16);
ARGUMENT(17);
ARGUMENT(18);
ARGUMENT(19);
ARGUMENT(20);
ARGUMENT(21);
ARGUMENT(22);
FNVT_END;
}
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K, typename L, typename M, typename N, typename O, typename P, typename Q, typename R, typename S, typename T, typename U, typename V, typename W, typename X>
string Format(const string &str, const A &_0, const B &_1, const C &_2, const D &_3, const E &_4, const F &_5, const G &_6, const H &_7, const I &_8, const J &_9, const K &_10, const L &_11, const M &_12, const N &_13, const O &_14, const P &_15, const Q &_16, const R &_17, const S &_18, const T &_19, const U &_20, const V &_21, const W &_22, const X &_23)
{
FNVT_BEGIN;
ARGUMENT(0);
ARGUMENT(1);
ARGUMENT(2);
ARGUMENT(3);
ARGUMENT(4);
ARGUMENT(5);
ARGUMENT(6);
ARGUMENT(7);
ARGUMENT(8);
ARGUMENT(9);
ARGUMENT(10);
ARGUMENT(11);
ARGUMENT(12);
ARGUMENT(13);
ARGUMENT(14);
ARGUMENT(15);
ARGUMENT(16);
ARGUMENT(17);
ARGUMENT(18);
ARGUMENT(19);
ARGUMENT(20);
ARGUMENT(21);
ARGUMENT(22);
ARGUMENT(23);
FNVT_END;
}
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K, typename L, typename M, typename N, typename O, typename P, typename Q, typename R, typename S, typename T, typename U, typename V, typename W, typename X, typename Y>
string Format(const string &str, const A &_0, const B &_1, const C &_2, const D &_3, const E &_4, const F &_5, const G &_6, const H &_7, const I &_8, const J &_9, const K &_10, const L &_11, const M &_12, const N &_13, const O &_14, const P &_15, const Q &_16, const R &_17, const S &_18, const T &_19, const U &_20, const V &_21, const W &_22, const X &_23, const Y &_24)
{
FNVT_BEGIN;
ARGUMENT(0);
ARGUMENT(1);
ARGUMENT(2);
ARGUMENT(3);
ARGUMENT(4);
ARGUMENT(5);
ARGUMENT(6);
ARGUMENT(7);
ARGUMENT(8);
ARGUMENT(9);
ARGUMENT(10);
ARGUMENT(11);
ARGUMENT(12);
ARGUMENT(13);
ARGUMENT(14);
ARGUMENT(15);
ARGUMENT(16);
ARGUMENT(17);
ARGUMENT(18);
ARGUMENT(19);
ARGUMENT(20);
ARGUMENT(21);
ARGUMENT(22);
ARGUMENT(23);
ARGUMENT(24);
FNVT_END;
}
template<typename A, typename B, typename C, typename D, typename E, typename F, typename G, typename H, typename I, typename J, typename K, typename L, typename M, typename N, typename O, typename P, typename Q, typename R, typename S, typename T, typename U, typename V, typename W, typename X, typename Y, typename Z>
string Format(const string &str, const A &_0, const B &_1, const C &_2, const D &_3, const E &_4, const F &_5, const G &_6, const H &_7, const I &_8, const J &_9, const K &_10, const L &_11, const M &_12, const N &_13, const O &_14, const P &_15, const Q &_16, const R &_17, const S &_18, const T &_19, const U &_20, const V &_21, const W &_22, const X &_23, const Y &_24, const Z &_25)
{
FNVT_BEGIN;
ARGUMENT(0);
ARGUMENT(1);
ARGUMENT(2);
ARGUMENT(3);
ARGUMENT(4);
ARGUMENT(5);
ARGUMENT(6);
ARGUMENT(7);
ARGUMENT(8);
ARGUMENT(9);
ARGUMENT(10);
ARGUMENT(11);
ARGUMENT(12);
ARGUMENT(13);
ARGUMENT(14);
ARGUMENT(15);
ARGUMENT(16);
ARGUMENT(17);
ARGUMENT(18);
ARGUMENT(19);
ARGUMENT(20);
ARGUMENT(21);
ARGUMENT(22);
ARGUMENT(23);
ARGUMENT(24);
ARGUMENT(25);
FNVT_END;
}
/***************************************************************************************/