http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2087.pdfsprintf()
で説明されているように、再帰的な可変個引数テンプレートを使用する代わりの方法を書いています。私の目標は、ユーザー定義型のカスタム データ型フォーマッタを簡単に追加できるようにすることです。たとえば、基本的な実装が次のようになっているとします。
#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");
}
次に、次のように記述して、自分のクラス(たとえば、 a を返すFoo
メソッドを含む) のフォーマッタを追加できます。customDescription()
wstring
template<typename... Args>
const wstring wsprintf<const Foo&>(const wchar_t *s, const Foo& foo, const Args&... args)
{
return wsprintf(s, foo.customDescription(), args...);
}
私はこれを行うことができます:
Foo bar;
wstring message = wsprintf("my foo tells me %s", bar);
ただし、 http://www.gotw.ca/publications/mill17.htmで説明されているように、関数の部分的なテンプレートの特殊化 (PTSF) が許可されていないため、このコードを書いた方法は機能しません。
PTSF の代わりに一般的に利用できる 2 つの代替手段は次のとおりです。
- テンプレートの使用を完全に排除し、オーバーロードされた関数を使用します。
- 関数の特殊な実装をラップする静的クラスを作成します。
printf()
再帰的な可変個引数テンプレート アプローチには少なくとも 1 つのテンプレート引数 (可変個引数パック)が必要なため、最初の選択肢は実行可能ではないようです。
2 番目の方法を実装しようとしたときに、いくつかの構文エラー (コメントとしてインライン) に遭遇しました。
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
}
これらのエラーを修正する方法がわかりません。何か案は?そもそも私は正しい道を進んでいますか?