Formatの続き

早速つくってみました。
結構思ったとおりできたかも。。
使い方は簡単で

std::cout << Format("$1") % "abc" << std::endl;

のようにすれば$1が文字列のデフォルト書式"%s"に代わります。

std::cout << Format("$1") % 1 << std::endl;

なら"%d"です。
まーこのへんは適当でw

ちなみに"%03d"とかの指定はCustomForm関数をつかって

std::cout << Format("$1") % CustomForm(1,"%03d") << std::endl;

のようにします。
ただCustomForm使うと依然としてCustomForm("abc","%d")みたいなぶっ飛ぶ処理をいれられますので
この辺は注意が必要です(いみねーw
挙句に仕様のとおり$とか%の文字はそのまま送りますので

std::cout << Format("$1%") % 50 << std::endl;
std::cout << Format("$1$1") % "です" << std::endl;//「$1です」と表示したい
std::cout << Format("$$1です") % 1 % << std::endl;// こっちはOK

%はそのまま内部で呼ばれるsprintfに引っかかってぶっ飛ぶでしょう。
$文字自体は問題なく出力しますが$1のように後に数字がくると文字ではなく引数と解釈されるので「ですです」と出力されます。
$$1とかやっても$$->$という内部処理してないのでだめです。
↑のFormat("$$1です") は[$ $1 です]の$1が数字の1に変換されて
[$1です]に変化したものなので意味が違います。
一つの手としては$と%は最後に渡すくらいしかないでしょうね。

std::cout << Format("$1$2") % 50 %'%' << std::endl; //50%
std::cout << Format("$2$1") % "です" %"$1" << std::endl; //$1です

で、手持ちのプロファイラで100回ループの速度チェックしてみました。
かなり遅くなりますね><
まぁ機能としてboostよりかなりしょぼいだけあって
若干速度でてるかなぁ・・・
時間の単位はマイクロセカンドです。1,000,000が1秒ですね。

2,830.8	        (boost::format("%1% %2% %3$04d %4% %5%\n") %"abc" %3 %3 %c %ul).str();	
1,770.1	        (Format("$1 $2 $3 $4 $5\n") %"abc" %3 %CustomForm(3,"%04d") %c %ul).Value();	
201.0	        sprintf(buf,"%s %d %04d %c %d\n","abc",3,3,c,ul);	
				
1,161.6	        (boost::format("%1%\n") % "abc").str();	
340.7	        (Format("$1\n") %"abc").Value();	
65.4	        sprintf(buf,"%s\n","abc");	

最後にソースを。

#include 
#include 

#include 

struct Format;

template 
struct CustomFormat
{
    CustomFormat(const T& t,const std::string& f)
        :ft(t),ff(f){}
    void Invoke(Format& f) const
    {
        f.SetFormat(ff);
        f % ft;
    }
    const T& ft;
    const std::string& ff;
};

template 
CustomFormat CustomForm(const T& t,const std::string& f)
{
    return CustomFormat(t,f);
}

struct Format
{
    Format(const std::string& s)
        :fs(s),fi(0)
    {
    }
#define DEFINE_FORMAT_OPERATOR(a,b,c,d)\
    Format& operator%(a v)\
    {\
        ++fi;\
        static const std::string cFormat( (b) );\
        bool ShouldReplace=Check(ff.empty()?cFormat:ff);\
        JAM_ASSERT(ShouldReplace);\
        do\
        {\
            fbuf.reserve(fs.length()+1+(c));\
            sprintf(&fbuf[0],fs.c_str(),(d));\
            fs.assign(&fbuf[0]);\
        }\
        while(Check(ff.empty()?(b):ff));\
        ff.clear();\
        return *this;\
    }
    DEFINE_FORMAT_OPERATOR(const std::string&,"%s",v.length(),v.c_str())
    DEFINE_FORMAT_OPERATOR(char,"%c",64,v)
    DEFINE_FORMAT_OPERATOR(unsigned char,"%u",64,v)
    DEFINE_FORMAT_OPERATOR(short,"%d",64,v)
    DEFINE_FORMAT_OPERATOR(unsigned short,"%u",64,v)
    DEFINE_FORMAT_OPERATOR(int,"%d",64,v)
    DEFINE_FORMAT_OPERATOR(unsigned int,"%u",64,v)
    DEFINE_FORMAT_OPERATOR(long,"%d",64,v)
    DEFINE_FORMAT_OPERATOR(unsigned long,"%u",64,v)
    DEFINE_FORMAT_OPERATOR(long long,"%I64d",128,v)
#undef DEFINE_FORMAT_OPERATOR

    template 
    Format& operator%(const CustomFormat& v)
    {
        v.Invoke(*this);
        return *this;
    }
    void SetFormat(const std::string& format)
    {
        ff=format;
    }
    const std::string& Value()
    {
        return fs;
    }
private:
    bool Check(const std::string& format)
    {
        static const std::string wArgTab[]=
        {
            "$1",
            "$2",
            "$3",
            "$4",
            "$5",
            "$6",
            "$7",
            "$8",
            "$9",
            "$10",
            "$11",
            "$12",
            "$13",
            "$14",
            "$15",
            "$16",
            "$17",
            "$18",
            "$19",
            "$20",
        };
        std::string::size_type index=fs.find(wArgTab[fi-1]);
        if(index!=std::string::npos)
        {
            fs.replace(index,wArgTab[fi-1].length(),format);
            return true;
        }
        return false;
    }
    unsigned long fi;
    std::string fs;
    std::string ff;
    std::vector fbuf;
};

template 
std::basic_ostream& operator<<(std::basic_ostream& o
                                           ,Format& f)
{
    o << f.Value();
    return o;
}