2014-12-01 3 views
4

Предисловие. Я пытаюсь получить более глубокое понимание метапрограммирования шаблонов C++, и кажется, что я застрял ... Я пишу библиотеку, которую мы будем использовать для сериализации двоичных данных [de]. Ожидаемая структура распакованных данных известна в определенной степени, и мне представляется разумным использовать эти знания для: (1) проверки данных (2) пропускать нерелевантные части и (3) распаковывать данные непосредственно в структуры, известные во время компиляции - как избежать ненужного копирования, так и сделать код клиента более чистым.Реализация статической версии std :: all_of с использованием метапрограммирования шаблонов?

Так, например, я хочу реализовать функцию, которая распаковывает массив (массивы могут содержать гетерогенные данные, например, в JSON). Для простоты предположим, что массив имеет фиксированный размер и не имеет гнездования.


Реальная проблема Я хочу, чтобы написать функцию, которая будет принимать входной буфер, содержащий данные, преобразованные в последовательную форму (или поток - это не имеет значения, в нашем контексте) и std::tuple, содержащий lvalues ​​для вывода (пакет параметров - худшая альтернатива, потому что мне придется иметь дело с гнездом в конце концов). Поэтому мне сначала нужно проверить, подходят ли все типы в кортеже для распаковщика и дать соответствующее сообщение об ошибке, если они не являются.

Так что код что-то вроде:

template<typename T> 
struct is_integral_lvalue : std::integral_constant<bool, 
          std::is_lvalue_reference<T>::value && 
          std::is_integral<T>::value && 
          (sizeof(T) == 4 || sizeof(T) == 8)> 
{ 
}; 

/* ... */ 
template<typename TInputBuffer, typename... TDest> 
static TRet unpack_int_tuple(TInputBuffer src_buf, std::tuple<TDest...> &&dest) noexcept(is_noexcept) 
{ 
    static_assert(typelist::all_are<is_integral_lvalue, TDest...>::value, 
        "All types in a tuple must be integral lvalue-references"); 
    /* do unpacking */ 
} 

условия, is_integral_constant может быть несколько произвольно. Поэтому желательно, чтобы шаблон all_are мог использовать любой унарный предикат. Возникает вопрос: что я должен писать в typelist::all_are (и, может быть, что мне следует исправить в приведенном выше коде, чтобы можно было написать такой all_are)?

Рабочий пример был бы идеальным, конечно, но я буду признателен за общие идеи/советы, если они будут полезны.

Ограничения Моя цель - не только реализовать эту функцию, но и понять, как она работает (такое решение, как «просто использовать boost :: mpl» или «boost :: hana», не подходит). Чем меньше несвязанных вещей мы используем, тем лучше. Предпочтительно код должен быть в C++ 11 (мы еще не готовы использовать C++ 1y/GCC 4.9). Я также надеюсь, что можно избежать использования макросов препроцессора.

Некоторые вещи, которые я googled. Boost.MPL, конечно, может быть использован, но он большой, он использует медленные рекурсивные шаблоны (вместо variadics), и трудно понять, что «под капотом». Boost :: hana, к сожалению, основан на полиморфных лямбдах, которые не попадали в C++ 11. Я видел эту библиотеку https://github.com/Manu343726/Turbo, но кажется, что для ее использования требуется слишком много изменений в коде (чтобы обернуть почти все типы в своих адаптерах). Он также использует такие вещи, как ленивая оценка (при расширении шаблонов) - здесь это не нужно, и код будет намного сложнее читать.

Эта библиотека https://github.com/ldionne/mpl11 является почти что мне нужно. Проблема опять же связана с обертками: and_ реализован как особый случай metafunction foldr (который разворачивается для лучшей производительности во время компиляции). И все они используют использование метафлора, ленивость и т. Д., Что делает его очень трудным для понимания (за исключением, может быть, для опытных программистов на функциональном языке). Так что для меня было бы достаточно объяснения, как пропустить все эти очень обобщенные и сложные методы и написать тот же шаблон and_, но более простым способом (для более конкретного использования).

+0

Рад видеть, что кто-то думает об использовании моей библиотеки, даже если ее окончательно отклонили. Большое спасибо :) – Manu343726

ответ

6

До C++ 17 и fold expressions приходят, прямолинейный реализация all_of является:

// base case; actually only used for empty pack 
template<bool... values> 
struct all_of : std::true_type {}; 

// if first is true, check the rest 
template<bool... values> 
struct all_of<true, values...> : all_of<values...> {}; 

// if first is false, the whole thing is false 
template<bool... values> 
struct all_of<false, values...> : std::false_type {}; 

В этом случае использование становится

static_assert(all_of<is_integral_lvalue<TDest>::value...>::value, 
       "All types in a tuple must be integral lvalue-references"); 

Если вы хотите сохранить оригинальный синтаксис, это легко с помощью псевдонима:

template<template <class> class T, class... U> 
using all_are = all_of<T<U>::value...>; 

Кроме того, s ошибка в вашем is_integral_lvalue - ссылочный тип не является интегральным типом. Ваша проверка is_integral должна быть сделана на typename remove_reference<T>::type, а не только T.


Edit: здесь более простой реализации all_ofcourtesy of @Columbo:

template<bool...> struct bool_pack; 

template<bool...values> struct all_of 
    : std::is_same<bool_pack<values..., true>, bool_pack<true, values...>>{}; 
+0

Я бы не назвал это ссылочным типом, учитывая тип 'T', если вы используете' T && 'в шаблоне, вы в основном разрешаете что-либо, вот что Скотт Мейерс называет универсальной ссылкой. – user2485710

+1

@ user2485710 inb4 терминология устарела. То, что вы ищете сейчас, - это «[справочная ссылка] (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4164.pdf)». –

+2

@ user2485710 Ошибка в проверке 'std :: is_lvalue_reference :: value' и'std :: is_integral :: значение' одновременно. Они никогда не могут быть истинными. –

0

Не-MPL версия and_ предлагается here, теперь переименован в conjunction.

Реализация была в libstdC++ (как std::__and_ в <type_traits>) давно.

Here - моя простая реализация (с менее явными специализациями).

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