2

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 つの代替手段は次のとおりです。

  1. テンプレートの使用を完全に排除し、オーバーロードされた関数を使用します。
  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
}

これらのエラーを修正する方法がわかりません。何か案は?そもそも私は正しい道を進んでいますか?

4

1 に答える 1

4

問題は、クラスクラス テンプレートの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 ... 
};
于 2012-04-18T12:00:33.163 に答える