也许monad:如何避免在Maybe <t>实例中存储T型值?

时间:2015-12-16 21:28:32

标签: c++ templates c++11 monads

在下面的coliru中,您将找到我对“Maybe”monad的实现。

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

我遇到的问题是“Nothing”值带有一个不必要的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 个答案:

答案 0 :(得分:2)

在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的{​​{1}}数组,保持未初始化,并使用实际创建sizeof(T)类型的对象时放置新。这种方法被描述为here

最后,回答你的上一个问题:不,没有更简单的方法可以做到这一点:

T

根据我之前的说法,应该看起来像

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