我正在编写sprintf()
使用递归可变参数模板的替代方法,如http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2087.pdf中所述。我的目标是允许为用户定义的类型轻松添加自定义数据类型格式化程序。例如,如果基本实现如下所示:
#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");
}
然后我可以通过编写为我的类添加一个格式化程序Foo
(比方说,它包含customDescription()
返回 a的方法)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);
但是,我编写此代码的方式将不起作用,因为不允许函数的部分模板专业化 (PTSF),如http://www.gotw.ca/publications/mill17.htm中所述。
通常可替代 PTSF 的两种替代方法是:
- 完全消除模板的使用并使用重载函数。
- 创建静态类来包装函数的专门实现。
第一种选择似乎不可行,因为递归可变参数模板方法printf()
需要至少一个模板参数(可变参数包)。
当我尝试实现第二种选择时,我遇到了几个语法错误(作为注释内联):
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
}
我不确定如何解决这些错误。有任何想法吗?我一开始就走在正确的道路上吗?