具有递归可变参数模板的函数的部分模板特化的替代方法

时间:2012-04-18 11:55:50

标签: c++ c++11 template-specialization variadic-templates

我正在使用递归可变参数模板编写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添加格式化程序(假设,它包含通过编写<{1}}的方法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...);
}

但是,我编写此代码的方式不起作用,因为不允许对函数(PTSF)进行部分模板特化,如http://www.gotw.ca/publications/mill17.htm中所述。

通常可用的两种替代方案代替PTSF:

  1. 完全消除模板的使用并使用重载功能。
  2. 创建静态类以包装函数的专用实现。
  3. 第一种选择似乎不可行,因为Foo bar; wstring message = wsprintf("my foo tells me %s", bar); 的递归可变参数模板方法需要至少一个模板参数(可变参数包)。

    当我尝试实现第二种选择时,我遇到了几个语法错误(内联作为注释):

    printf()

    我不确定如何解决这些错误。有任何想法吗?我首先走的是正确的道路吗?

1 个答案:

答案 0 :(得分: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 ... 
};