2012-04-18 1 views
2

Я пишу альтернативу 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(), который возвращает 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); 

Однако, как я написал этот код не будет работать, потому что часть ial шаблона для функций (PTSF) не допускается, как объясняется в http://www.gotw.ca/publications/mill17.htm.

Две альтернативы, как правило, доступны вместо PTSF являются:

  1. Исключите использование шаблонов в целом и использовать перегруженные функции.
  2. Создание статических классов для переноса специализированных реализаций функции.

Первый вариант не представляется возможным, так как рекурсивная VARIADIC шаблон подход к printf() требует по меньшей мере, один шаблон аргумент (параметр VARIADIC пакета).

Когда я попытался реализовать второй вариант, я столкнулся с несколькими ошибками синтаксиса (встроенный в комментариях):

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 ... 
}; 

 Смежные вопросы

  • Нет связанных вопросов^_^