Моя собственная функция формат в C++


Я никогда не был доволен любым из возможных функции sprintf()функции в C++:

  • функции sprintf() - это функции C, и это очень опасно для использования (неопределенное поведение повсюду)
  • импульс::формат слишком медленно и неудобно использовать (думаю % синтаксис)
  • библиотеки iostream является крайне неудобным в использовании

Поэтому я придумал мой собственный. Таковы мои требования:

  • Вдохновленный функции C формат#ы
  • Никогда не должны потерпеть неудачу во время выполнения, никогда не Аварии и не имеют неопределенное поведение, независимо от того, что вы называете его. Следует не во время компиляции, когда это возможно, вместо.
  • Должна быть расширяемой (если вы создаете класс человек, то вы можете сдать человека в функцию объекта)
  • Должен быть быстрым
  • Строка формата должна быть легко локализовать
  • Формат строки не должны иметь заполнители, чей синтаксис зависит от аргумента типа (т. е. без ВС )
  • Должно быть достаточно "нормальный" синтаксис (без % как повысить::формат)

Меня интересуют отзывы на удовлетворении вышеуказанных требований. Меня особенно интересуют комментарии с точки зрения конечного пользователя и меньше о внутренностях код (т. е. код, который скрыт от конечного пользователя).

Несколько примеров:

// 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);

Это мои модульные тесты:

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");
}

Обратите внимание, что в связи с C++ ограничения (отсутствие шаблонов с переменным числом аргументов) код точно не довольно. Также этот код является частью большой библиотеки, поэтому он не будет компилировать свои собственные.

/****************************************************************************************
 * 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;
}

/***************************************************************************************/


Комментарии
3 ответа

Есть некоторые серьезные переносимости-проблемы с кодом:


  • Вам не хватает заголовка охранников. #ПРАГМА является нестандартным.

  • Вы не имеете надлежащего включает в себя (из-за предкомпилированного заголовка, я полагаю).

  • Имена, начинающиеся с подчеркивания, за которым следует прописная буква (например, _FinalizeFormat, _FindPlaceholder) зарезервированы компилятором.

10
ответ дан 2 мая 2011 в 12:05 Источник Поделиться

На мой взгляд:


  • Использование полномасштабных имена (как СТД::вектор, тип Boost::shared_ptr)

  • Не используйте модификатор const & для простых типов (например инт или двойной)

  • Писать константный после типа: СТД::строка константная&

  • Для строки IntToString(...) и метод toString(пост двойной &Вэл...) почему вы не используете функции std::ostringstream?

  • В FormatNoVariadicTemplates.ч почему вы не используете функции для FNVT_BEGIN и FNVT_END?

У вас есть некоторые результаты тестов?

ЗЫ: хорошая идея ;)
Я обычно использую в Qt функции, мы используем эту библиотеку в своих проектах или STL.

7
ответ дан 30 апреля 2011 в 03:04 Источник Поделиться

У меня есть несколько замечаний, в частности, нет порядка.

Мне кажется, что вы не можете решить между СТД::строка и константный тип char*. Выбери одну из них.

(Может быть, я получу обругают за это.) Вы говорите, что вы заботитесь о производительности, но использовать вектор и строку рассказывают другую историю. Мне кажется, что выделения кучи совершенно ненужных для всего этого, и по этой причине я хотел бы избежать STL и с++ строк. Или, если не избежать их полностью, я хотел бы избежать, используя так много СТД::строкаs в качестве временных конструкций при форматировании. Функции, которые делают это, должны взять целевой буфер в качестве параметра.

Кажется странным, что ваше внутреннее представление вариантов остается строкой во все времена. Например:

static const char *normalStrings[] = { "true", "false" };
static const char *alternativeStrings[] = { "yes", "no" };
const bool alternative = (options == "a");
const char **strings = alternative ? alternativeStrings : normalStrings;

Это само по себе является немного сложно для постороннего следовать как написано, но помимо этого, ты действительно хочешьвариантов == "а"? Что, если вы хотите больше, чем один вариант? Не проверка в более как функции strchr(параметры "а")? В этом случае я бы сказал, что вы действительно хотите о(n) для поиска вариантов? Может быть, это не имеет смысла, как струна. Может быть, вы хотите, чтобы хранить их внутри, как флаги в целое. Даже если вы не хотите, чтобы объединить функции он по-прежнему может выглядеть менее странно как перечисление или постоянной. Есть много магические литералы с плавающей вокруг в этот код.

Есть много кода, который более многословен, чем он должен быть, например:

/* 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;

В для петли, кажется, изобретать функции strchr. Я бы предпочел что-то вроде этого:

char *current, *end;

while ((current=strchr(str, '{')) &&
(end=strchr(current, '}')))
{
//
// TODO: do something with placeholder at (current, end)
//

str = end + 1;
}

Или, возможно, более C-подобных (хотя я понимаю, что вы пишете на C++, похоже, вы уже отказались от ряда идиом) будет что-то вроде этого:

while (*str)
{
if (*str == '{' &&
(end=strchr(str, '}')))
{
//
// TODO: evaluate placeholder at (str, end) into dst
//

str = end+1;
}
else
{
// TODO: make sure this doesn't overflow :-)
*dst++ = *str++;
}
}

IntToString может быть много усовершенствований... одна банальная стилистическая дело в том, что "0123456789" намного легче на глазах, чем { '0', '1', '2', ... }. Что еще более важно, вы должны сделать это с отдельной куче? Может быть, она должна быть передана в буфер назначения. В резервный метод вызывается с постоянным и выглядит немного странно, потому что ты только что сделал конвертацию внутри ТМП, так что вы знаете точную длину...

Наконец, как дело привычки, если вы собираетесь использовать функции sprintf -- ну нет. Использовать и snprintf, вместо. (Если вам случится быть с использованием версии Visual Studio, что нет, там же sprintf_s или StringCchPrintf.)

5
ответ дан 6 мая 2011 в 11:05 Источник Поделиться