C概念:我可以定义一个本身就是模板的概念吗?

对不起,如果问题不太清楚.我不确定用它来表达它的最佳方式(随意编辑!).我认为一个例子是最清楚的:

我试图定义一个基于Haskell definition的Monad概念.绑定运算符(>> =)要求A类型的Monad可以绑定到一个带有A的函数并返回一个B类型的Monad.可以根据value_type typedef定义A,但如何在我的概念中定义类型B?

template <typename M>
concept bool Monad()
{
  return requires(M m, Function<_1, ValueType<M>> f) {
    // (>>=) :: m a -> (a -> m b) -> m b
    { m >>= f } -> M
  }
}

在上面的例子中,我在Function<>中用什么来代替_1?概念?

这也足以将调用f的结果限制为任何类型的Monad吗?

最佳答案 我认为你能做的最接近的是提供一个特定的功能,即A – >单子< B个并验证它做对了.为了防止无限递归,我们可以验证A – > M作品:

template <class M>
concept bool Monad()
{
    return requires(M m) {
        { m >>= std::function<M(ValueType<M>)>{} } -> M;
    };
}

这只是一个具体案例,但我不相信有可能验证A – >的一般情况.单子< X>因为概念检查仍然涉及特定表达式,您只能创建具有特定类型的特定表达式.

当然,我们可以提供多种此类要求.使用重新绑定元函数:

template <class M, class X>
struct rebind;

template <class M, class X>
using rebind_t = typename rebind<M, X>::type;

template <template <class...> class Z, class R, class X>
struct rebind<Z<R>, X> {
    using type = Z<X>;
};

然后我们可以为返回各种类型的函数添加需求,比如它也适用于int:

template <class M>
concept bool Monad()
{
    return requires(M m)
    {
        { m >>= std::function<M(ValueType<M>)>{} } -> M;
        { m >>= std::function<rebind_t<M,int>(ValueType<M>)>{} } -> rebind_t<M,int>;
    };
}

通过将其重构为自己的子概念可能会变得更容易:

template <class M, class R>
concept bool MonadBind()
{
    return requires(M m) {
        { m >>= std::function<rebind_t<M,R>(ValueType<M>)>{} } -> rebind_t<M,R>;
    };
}

template <class M>
concept bool Monad()
{
    return requires(M m) {
        requires MonadBind<M, ValueType<M>>();
        requires MonadBind<M, int>();
    };
}
点赞