2011-01-25 26 views
1

私はテンプレートプログラミングのスキルを拡張しようとしていますが、私は正しい解決策が見当たらないという問題に直面しています。 これは、より高度なテンプレート作成を行うための個人的なトレーニングです。テンプレートプログラミングに関する助けが必要

この目標は、フォーマット文字列のタイプに応じて、整数型(sprintfまたはswprintfを使用)を文字列またはwstringに変換するためのテンプレートを作成することです。 エラーチェックの必要はありません(今のところはありません)。私は可変フォーマットのCHAR型を決定する必要があることのいずれかのため"%i"又はL"%i" としてデフォルトリテラル値を供給する必要

(const char*) NULLとして、または(const wchar_t*) NULL

問題は形式が指定されている場合であります。 私は今、SFINAEを使ってそのための関数を使用しています。 しかし、私はそのための変数を使用したいと思いますが、私はSFINAY varaiablesで動作しないと思う(または私は間違っています)。ここで

は、これまでのところ、私の(作業)コードです:

//////////////////////////////////////////////////////////////////////////////// 

template < typename T ,typename I > 
inline 
typename std::enable_if< std::is_same< T ,char >::value ,int >::type 
str_printf (T* szBuff ,int iLen ,const T* szFrmt ,I iNum) 
{ return sprintf_s(szBuff ,iLen ,szFrmt ,iNum); } 

template < typename T ,typename I > 
inline 
typename std::enable_if< std::is_same< T ,wchar_t >::value ,int >::type 
str_printf (T* szBuff ,int iLen ,const T* szFrmt ,I iNum) 
{ return swprintf_s(szBuff ,iLen ,szFrmt ,iNum); } 

//////////////////////////////////////////////////////////////////////////////// 

template < typename T > 
inline 
typename std::enable_if< std::is_same< T ,char >::value ,const char* >::type 
Dflt_Frmt() { return "%i"; } 

template < typename T > 
inline 
typename std::enable_if< std::is_same< T ,wchar_t >::value ,const wchar_t* >::type 
Dflt_Frmt() { return L"%i"; } 

//////////////////////////////////////////////////////////////////////////////// 

template < typename T ,typename I > 
inline 
std::basic_string< T ,std::char_traits <T> > 
to_string (I iNum ,const T* pszFrmt) 
{ 
    const int iLen (65); 
    T szBuff [iLen] = {0}; 

    std::basic_string< T ,std::char_traits <T> > frmt ((pszFrmt && (*pszFrmt)) ? pszFrmt : Dflt_Frmt<T>()); 
    str_printf(szBuff ,iLen ,frmt.c_str() ,iNum); 

    return szBuff; 
} 

//////////////////////////////////////////////////////////////////////////////// 

この私がやりたいものをこの(明らかにそれが働いていない)

​​

私はsimillar方法でこれを行うことができますまたは作業バージョンが最善の方法ですか? またはこれを行う方法>

私は文字列ストリームを使用するための提案は必要ありません(これはこの質問に関するものではありません)。

MSVS 2010を使用しています(申し訳ありませんが、後押しはありません)。

ありがとうございます。

+0

より良い仕様で始まり、いくつかのサンプルコードと望ましい出力(単体テストのスタイルで良いでしょう)。これにより、これらすべてのテンプレートのポイントを理解して、どこにでも出てくる呼び出しを増やすことがずっと簡単になります。 –

答えて

2

率直に言って、これは私が考えることができる唯一のソリューションです:それはきれいではありませんが、それは動作します

template <typename T> struct Dft { static const T* value; }; 
template <> const char* Dft<char>::value = "%i"; 
template <> const wchar_t* Dft<wchar_t>::value = L"%i"; 

template < typename T ,typename I > 
inline 
std::basic_string< T ,std::char_traits <T> > 
to_string (I iNum ,const T* pszFrmt) 
{ 
    const int iLen (65); 
    T szBuff [iLen] = {0}; 

    std::basic_string< T ,std::char_traits <T> > frmt ((pszFrmt && (*pszFrmt)) ? pszFrmt : Dft<T>::value); 

    str_printf(szBuff ,iLen ,frmt.c_str() ,iNum); 

    return szBuff; 
}; 

+0

私はそれが私のものよりもはるかに説明的であると思います。ありがとう。 –

1

2番目のコードブロックでenable_ifを使用すると、テンプレートの署名で使用していないため、ハードエラーになります。変数dftのタイプを計算するには、boost::mpl::if_のようなものが必要です。私はあなたのフォーマットを両方のケースで動作させるために、狭い文字列から広い文字列にキャストすることができると信じています。

+0

@Jeremiah Willcock:あなたのreponsありがとう。私はキャストの提案を感謝します。あなたは署名の議論を詳しく説明できますか?私はそれがあなたが何を意味しているかを十分に理解していません。 –

+0

'enable_if'を使用すると、テンプレート引数に基づいて特定のオーバーロードや特殊化を選択するかどうかを制御できますが、コンパイラは関数やクラスの本体をインスタンス化するときに、 。したがって、 'enable_if'がそこで失敗すると、コンパイラはエラーを出力します。基本的には、使用するテンプレートの選択肢から脱却するのは「遅すぎる」です。 –

+0

@Jeremiah Willcock:はい、私はそれに賛成でした。 –

0

IMO、あなたがここでやろうとしていることは、かなり絶望的な試みです。 "%i"変換は浮動小数点型ではなく整数でのみ機能するため、コードはIint の場合にのみ機能します。他のタイプの場合、ユーザは、コードが定義された動作をするために、(正しい)フォーマット文字列をに渡す必要があります。現時点では、私はこの問題を無視し、Iintではない場合、ユーザーが(正しい)形式の文字列を渡すと仮定します。

将来的にはいくつか他のものに拡張したいかもしれませんが、今のところフォーマット文字列のタイプには2つの可能性があります:char *またはwchar_t *です。(あなたが主張する場合、または専門)、物事を処理するための正しい方法は、単純な過負荷であるような場合であること、それが思われること:

template <class T> 
std::string to_string(T val, char *fmt = "%i") { 
    // for the moment using `sprintf`, simply because every knows it -- not really 
    // advising its use in production code. 
    char buffer[256]; 
    sprintf(buffer, fmt, val); 
    return std::string(buffer); 
} 

template <class T> 
std::wstring to_string(T val, wchar_t *fmt = L"%i") { 
    wchar_t buffer[256]; 
    wsprintf(buffer, fmt, val); 
    return std::wstring(buffer); 
} 

今、あなたは、基本的に何かを「タイプのスイッチ」をやっていますこれはC++ではほとんどの場合回避できます(一般的に避けてください)。実行時ではなくコンパイル時にそれをやっている(またはとにかくしようとしている)マイナーな詳細は、それを実際に変更するものではありません。

さて、(あなたはIunsigned intであり、値がintのように表すことができる範囲内であれば、それは動作するはずだと主張することができるかもしれないが、それはあなたが望むことができる最高のことですそれでも非常に疑わしい)。

+0

ところで、これらのオーバーロードは、単一のパラメータで呼び出すとあいまいです。しかし、もちろん、あなたが言ったように、どちらの型のto_string関数テンプレートのまっすぐな古き良き特化が機能します。 –

+0

@Mikael:おっと、そうです。私もちょっと怠け者だよ... –

+0

あなたの答えをありがとう。しかしここでの問題は、to_string(...)を実装する方法ではありません。これは、テンプレートプログラミングの練習です。 –

関連する問題