2012-04-18 9 views
2

http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2087.pdfで説明されているように、再帰的バリデーションテンプレートを使用してsprintf()の代替案を書いています。私の目標は、ユーザー定義型のカスタムデータ型フォーマッタを簡単に追加できるようにすることです。例えば、基本的な実装は次のように見える場合:再帰的なバリデーショナルテンプレートを持つ関数の部分テンプレートの特殊化への代替

#include <iostream> 
#include <sstream> 
#include <wchar.h> 
#include <stdexcept> 

using std::wstring; 
using std::wstringstream; 

const wstring wsprintf(const wchar_t *s) 
{ 
    wstringstream outstream; 
    while(*s) 
    { 
     if (*s == L'%' && *++s != L'%') 
      throw std::runtime_error("invalid format string: missing arguments"); 
     outstream << *s++; 
    } 
    return outstream.str(); 
} 

template<typename T, typename... Args> 
const wstring wsprintf(const wchar_t *s, const T& value, const Args&... args) 
{ 
    wstringstream outstream; 
    while(*s) 
    { 
     if(*s == L'%' && *++s != L'%') 
     { 
      outstream << value << wsprintf(++s, args...); 
      return outstream.str(); 
     } 
     outstream << *s++; 
    } 
    throw std::runtime_error("extra arguments provided to wsprintf"); 
} 

が、私は

template<typename... Args> 
const wstring wsprintf<const Foo&>(const wchar_t *s, const Foo& foo, const Args&... args) 
{ 
    return wsprintf(s, foo.customDescription(), args...); 
} 
を書き込むことによって( wstringを返すメソッド customDescription()が含まれている、のは言わせ、)私のクラス Fooのためのフォーマッタを追加することができます

私は、これを行うことができるだろう。しかし

Foo bar; 
wstring message = wsprintf("my foo tells me %s", bar); 

、私はこのコードが一部であるため動作しません書いた方法http://www.gotw.ca/publications/mill17.htmで説明されているように、関数(PTSF)のテンプレート特殊化は許可されていません。

PTSFの代わりに、一般的に利用可能な2つの選択肢があります:

  1. 完全テンプレートの使用を排除し、オーバーロードされた関数を使用します。
  2. 関数の特殊な実装をラップするための静的クラスを作成します。 printf()への再帰可変長引数テンプレートアプローチは、少なくとも1つのテンプレート引数(可変引数パラメータパック)を必要とするため

最初の選択肢は、実現可能ないないようです。私は第二の代替を実装しようとしたとき

、私はいくつかの構文エラー(コメントとしてインライン)に走った:

namespace wsprintf_impl { 

    struct wsprintf 
    { 
     static const wstring impl(const wchar_t *s) 
     { 
      wstringstream outstream; 
      while(*s) 
      { 
       if (*s == L'%' && *++s != L'%') 
        throw std::runtime_error("invalid format string: missing arguments"); 
       outstream << *s++; 
      } 
      return outstream.str(); 
     } 
    }; 

    // ERROR: redefinition of 'wsprintf' as different kind of symbol 
    template< class T, class Args&... args > 
    struct wsprintf 
    { 
     static const wstring impl(const wchar_t *s, const T& value, const Args&... args) 
     { 
      wstringstream outstream; 
      while(*s) 
      { 
       if(*s == L'%' && *++s != L'%') 
       { 
        outstream << value << wsprintf::impl(++s, args...); 
        return outstream.str(); 
       } 
       outstream << *s++; 
      } 
      throw std::runtime_error("extra arguments provided to wsprintf"); 
     } 
    }; 

} 

template< class T, class Args&... args > 
wstring wsprintf(const wchar_t *s, const T& value, const Args&... args) 
// ERROR: type 'const Args &' of function parameter pack does not contain any unexpanded parameter packs 
// ERROR: declaration of 'args' shadows template parameter 
{ 
    return wsprintf_impl::wsprintf<T, args...>::impl(s, value, args...); 
    // ERROR: expected '>' 
    // ERROR: expected '(' for function-style cast or type construction 
} 

は、私はこれらのエラーを修正するかどうかはわかりません。何か案は?私は最初の正しい道にいますか?

答えて

3

wsprintfは、クラスクラステンプレートの両方として宣言されています。クラステンプレートにするだけです。最初のケースは引数なしの特殊化です:

template <typename...> 
struct wsprintf; 

template <> 
struct wsprintf<> // specialization for no arguments 
{ 
    // blah blah ... 
}; 

template< class T, class... Args> // oops, bad syntax here was 
struct wsprintf<T, Args...> // specialization for one or more args. 
{ 
    // blah blah ... 
}; 
関連する問題