Nano Hash - криптовалюты, майнинг, программирование

Реализация статической версии std::all_of с использованием метапрограммирования шаблонов?

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

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


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

Итак, код примерно такой:

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 в продакшене). Я также надеюсь, что можно избежать использования макросов препроцессора.

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

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


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

Ответы:


1

Пока не появятся C++17 и выражения сворачивания, простой реализацией 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...>;

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


Изменить: вот более простая реализация all_of любезно предоставлена ​​@Columbo:

template<bool...> struct bool_pack;

template<bool...values> struct all_of 
    : std::is_same<bool_pack<values..., true>, bool_pack<true, values...>>{};
01.12.2014
  • Я бы не назвал это ссылочным типом, учитывая тип T, если вы используете T&& в шаблоне, вы в основном позволяете входить чему угодно, это то, что Скотт Мейерс называет универсальной ссылкой. 01.12.2014
  • @ user2485710 inb4 терминология устарела. Сейчас вам нужен переадресация ссылка. 01.12.2014
  • @user2485710 user2485710 Ошибка заключается в одновременной проверке std::is_lvalue_reference<T>::value и std::is_integral<T>::value. Они никогда не могут быть одновременно правдой. 01.12.2014
  • @remyabel OP не указал версию C++, которую он хочет использовать, он отдал предпочтение C++11, мы уже говорим о C++17? 01.12.2014
  • @ user2485710 Это немного противоречиво. В проекте стандарта, который я использую, нет упоминания об универсальной ссылке. Насколько я знаю, Скотт Мейерс изобрел этот термин. 01.12.2014
  • Спасибо, исправил проверку is_integral_lvalue и воспользовался вашим решением - работает как положено, как раз то, что мне было нужно. Что касается универсальной ссылки: я думаю, что unpack_int_tuple перенаправит кортеж в фактическую функцию распаковки, поэтому я использовал ее. На самом деле не имеет значения, является ли кортеж lvalue или rvalue. Но это поля должны быть lvalues. 01.12.2014
  • @MikhailMaltsev ознакомьтесь с реализацией std::forward и std::move 01.12.2014
  • @MikhailMaltsev Кортеж принимается как ссылка на значение rvalue, а не как универсальная ссылка. Если вам нужна ссылка для пересылки, вам нужно взять весь тип в качестве параметра шаблона, а затем отдельно извлечь содержащиеся в нем типы. 01.12.2014
  • Как будет выглядеть решение со свернутыми выражениями? 01.12.2014
  • @ГерманДиаго template<bool... values> struct all_of : std::integral_constant<bool, (values && ...)> {};; или простой шаблон функции constexpr в том же духе. 01.12.2014
  • Я знаком с семантикой перемещения и переадресации. Я просто забыл, что сам кортеж здесь не является параметром шаблона. 01.12.2014
  • @remyabel на самом деле ничего не меняет, как вы называете что-то, это не так важно, если все знают, о чем идет речь. Что бы это ни стоило, комитет C++ также не дал этому предмету подходящего имени. 01.12.2014

  • 2

    Версия and_ без MPL предлагается здесь, теперь переименованный в conjunction.

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

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

    03.03.2016
    Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..