Упрощение создания шаблонных функций wchar_t / char с использованием признаков типа - PullRequest
0 голосов
/ 07 марта 2012

Я писал библиотеку файловой системы win32 и решил, что вместо того, чтобы использовать TCHAR, я хотел написать библиотеку шаблонов (только заголовок), которая работала бы с char / wchar_t независимо от опций компилятора / узкой ширины.

Это оставило меня с двумя проблемами:

  1. Моя библиотека должна была бы прозрачно / эффективно решить, вызывать ли ANSI / широкую версию оконных функций (например, CreateFileA или CreateFileW) в зависимости от того, какшаблон был расширен.
  2. В моей библиотеке иногда требовалось использовать строковые литералы, поэтому мне требовался способ перевода "строкового литерала в" или "L" "без создания затрат времени исполнения или путаницы в логике.

Я создал достаточно элегантное решение этих двух проблем, но я хотел, чтобы сообщество переполнения стека сообщало мне, есть ли какие-либо скрытые издержки / неприятности, связанные с ними.

Во-первых (для решения 1), поскольку мой класс шаблона имеет тип символа T, я создал следующеешаблоны / макросы в пространстве имен «detail» в моем классе:

// Selector template to choose between W and A versions of win32 functions
template<typename WF, typename AF> inline WF& select_w32func(AF &,        WF & pFuncW, wchar_t) { return pFuncW; }
template<typename WF, typename AF> inline AF& select_w32func(AF & pFuncA, WF &,        char)    { return pFuncA; }
template<typename T> inline T get_traits() { return NULL; }

#define SELECT_W32FUNC(x)    auto x = detail::select_w32func(::##x##A, ::##x##W, detail::get_traits<T>());
#define SELECT_W32FUNCS(x,y) auto x = detail::select_w32func(::x, ::y, detail::get_traits<T>());

Далее (для решения 2) я создал следующие шаблоны и макрос:

template<typename WC, typename AC> inline const WC* select_chartrait(const AC*,   const WC* b, wchar_t) { return b; }
template<typename WC, typename AC> inline const AC* select_chartrait(const AC* a, const WC*,   char)    { return a; }
template<typename WC, typename AC> inline const WC select_chartrait(const AC,     const WC b,  wchar_t) { return b; }
template<typename WC, typename AC> inline const AC select_chartrait(const AC a,   const WC,    char)    { return a; }

// Macro which allows string literals to be adapted by template parameter T
#define _S(x) detail::select_chartrait((x), (L##x), detail::get_traits<T>())

Это позволяет мне писатьконструкторы и функции-члены моего класса почти как если бы я не имел дело с шаблонными параметрами, например, следующий конструктор создает объект w32file со специальным идентификатором папки CSIDL в качестве его родителя:

basic_w32file(DWORD dwCSIDL, std::basic_string<T> & child) : m_name( MAX_PATH, ' ' )
{
  SELECT_W32FUNC(PathCombine);
  SELECT_W32FUNCS(strlen, wcslen);

  basic_w32file<T> parent( getSystemDirectory ( dwCSIDL, _S(' ')));
  if (child == _S(".") || child == _S(".."))
    PathCombine(&m_name[0], parent.getAbsoluteName().c_str(), child.c_str());
  else
    PathCombine(&m_name[0], parent.getPath().c_str(), child.c_str());

  m_name.resize( strlen(&m_name[0]) );
}

Как видите, макрос SELECT_W32FUNC переопределяет глобальное определение PathCombine с пространством имен и заменяет его ссылкой на функцию в версии A или W функции._S ("..") помещает правильный строковый литерал на место.

Мне кажется, что это будет очень эффективно, поскольку функции селектора шаблонов будут встроенными и в них практически не будет логики времени выполнения, что означает, что ониследует оптимизировать почти до нуля, это правильное предположение?

...