Возможно, монада: как избежать хранения значения T-типа в Maybe & lt; T & gt; пример?

В следующем coliru вы найдете мою реализацию монады «Возможно».

http://coliru.stacked-crooked.com/a/82978c254410ba6e

Проблема, которую я имею с этим, состоит в том, что ценности «Ничего» несут с собой ненужное Tтипизированный элемент данных, такой же, как «Just» значения, которые действительно нуждаются в этом.

Возможно ли реализовать Maybe<T> без значения «Nothing», столь же большого, как значения «Just», и не прибегая к динамическому распределению из Tзначения?

Я попытался определить Just<T> а также Nothing<T> как производные классы Maybe<T> с Just<T> будучи единственным классом, имеющим Tтип данных члена. Проблема в том, что тогда Monad<T>::bind лучше реализована как виртуальная функция-член, или, по крайней мере, для меня это наиболее естественно, и не может быть, потому что это также шаблон функции.

Кроме того, я хотел бы знать, есть ли более простой синтаксис, чем

template <typename Fun>
auto bind(Fun&& f) -> decltype(f(T{})) {
typedef typename decltype(f(T{}))::value_type R;
/*
* blabla
*/
}

добиться того же эффекта и овладеть R,

1

Решение

В C ++ компилятору необходимо знать размер объекта, с которым он работает, а объекты одинакового типа имеют одинаковые размеры. Когда это оказывается проблемой, появляются указатели и полиморфизм.

Это означает, что в вашем случае вы либо знаете размер заранее (и живете с sizeof(T) накладные расходы), или вы отступили к динамическому распределению. Последнее можно сделать разными способами: вы можете сделать Maybe<T> полиморфный, или вы можете выделить T сам.

Я не могу игнорировать некоторые проблемы с вашим кодом; оба связаны с одним раздражающим фактом: тип T может отсутствовать конструктор по умолчанию. Вы можете игнорировать это, или вы должны сделать некоторые исправления.

Во-первых, вы не можете сделать decltype(f(T{})), даже если T{} только для вывода типа и конструктор фактически не вызывается. Существует стандартный способ сделать это: std::declval<T>() возвращает объект типа T (и, фактически, вообще не реализован, только объявлен; этого достаточно для вывода типов). Итак, вы должны сделать decltype(f(std::declval<T>())),

Во-вторых, вы не можете просто объявить T _value, так как у вас нет конструктора для вызова при создании Nothing<T>, Это может быть просто решено с помощью динамического распределения, но есть другой способ (используется в boost::optional): хранить массив char размера sizeof(T), оставьте его неинициализированным и используйте размещение нового при создании объекта типа T, Этот подход описан Вот.

Наконец, отвечая на ваш последний вопрос: нет, не существует более простого способа сделать это:

typedef typename decltype(f(T{}))::value_type R;

который, по моим предыдущим словам, должен выглядеть

typedef typename decltype(f(std::declval<T>()))::value_type R;
2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]