【问题标题】:C++ constexpr list with size in its type类型为大小的 C++ constexpr 列表
【发布时间】:2018-04-10 06:30:50
【问题描述】:

我正在尝试用 C++ 开发一个 constexpr 函数式列表数据结构。我也在尝试利用 cons list 方法的递归结构。我有几次尝试,对于那些,你可以看到我过去的问题。现在,我已经决定让尺寸成为字体的一部分,即。 `名单。这是代码:

#include <iostream>
#include <type_traits>

template <typename T, unsigned int N>
struct list {
    public:

    constexpr list(const T& head, const list<T, N-1> &tail)
    :_length{N}, _head{head}, _tail{tail}
    {}

    const unsigned int _length;
    const T _head;
    const list<T, N-1> _tail;
};

template <typename T, unsigned int N>
constexpr auto head(const list<T, N> &li) {
    return li._head;
}

template <typename T, unsigned int N>
constexpr auto tail(const list<T, N> &li) {
    return li._tail;
}

template <typename T, unsigned int N>
constexpr auto prepend(const T &new_head, const list<T, N> &li){
    return list<T, N + 1>{new_head,
                          list<T, N>{head(li), tail(li)}};
}

template <typename T>
struct list<T, 0>
{
    constexpr static const bool nil = true;
};

template <typename T>
using nil = list<T, 0>;

template <typename Functor, typename T, unsigned int N>
constexpr auto fmap(Functor f, const list<T, N> &li) {
    if constexpr(N == 0)
        return nil<T>{};
    else
        return list{f(head(li)), fmap(f, tail(li))};
}

template <typename T, unsigned int N>
std::ostream& operator<<(std::ostream& str, const list<T, N> &li) {
    if constexpr(N == 0)
        return str;
    else{
        str << head(li) << ' ' << tail(li);
        return str;
    }
}

int main(){
    constexpr auto f = [](int x){ return x * x; };

    constexpr list<char, 2> p2{'U', list<char, 1>{'S', nil<char>{}}};
    constexpr auto p3 = prepend('S', p2);

    constexpr list<int, 2> i1{1, list<int, 1>{2, nil<int>{}}};
    constexpr auto i2 = fmap(f, i1);

    std::cout << p3;
}

其中一些在某种程度上有效。 fmap 是阻止我的程序编译的那个。我得到了错误

prog.cc:47:16: 错误:没有可行的构造函数或推导指南来推导“列表”的模板参数 返回列表{f(head(li)), fmap(f, tail(li))};

prog.cc:47:34: 注意:在函数模板特化 'fmap' 的实例化中请求这里 返回列表{f(head(li)), fmap(f, tail(li))};

prog.cc:67:25:注意:在此处请求的函数模板特化 'fmap' 的实例化 constexpr auto i2 = fmap(f, i1);

prog.cc:8:15:注意:候选模板被忽略:无法推断模板参数“N” constexpr list(const T& head, const list &tail)

和类似的。我在这里迷路了,这个错误的原因是什么?似乎编译器正确地推断出参数N,正如它所说的N=2。我觉得我需要添加一些与大小为零的列表相关的基本案例,但无法弄清楚。

【问题讨论】:

  • 不应该是return list&lt;T, N&gt;{ f(head(li)), fmap(f, tail(li)) }吗?
  • 在函数prepend() 中你为什么不简单地返回list&lt;T, N + 1&gt;{new_head, li}?我错过了什么?
  • @MariusBancila 考虑到list 甚至更奇怪@ 缺少 move-ctor。
  • 你为什么需要_length,它是模板参数。
  • @MariusBancila 抱歉,这是过去实施的一个错误,我忘了在那里进行更改。对于_length,我认为只是习惯性的。是的,我可以删除它。

标签: c++ list


【解决方案1】:

您有一个错字:使用模板结构列表时缺少类型说明符。波纹管应该工作

template <typename Functor, typename T, unsigned int N>
constexpr auto fmap(Functor f, const list<T, N> &li) {
    if constexpr(N == 0)
        return nil<T>{};
    else 
        return list<T, N-1>{f(head(li)), fmap(f, tail(li))};
}

【讨论】:

  • 我虽然编译器可以从参数中推断出它,但我猜fmap 的递归使用会让它大吃一惊。
  • @meguli 不,你错了。编译器无法推导出模板参数,因为当模板参数仅用于非推导上下文(函数中的 Functor 的情况)时,模板参数推导不考虑它
  • 我没有在 main 中使用显式模板调用 fmap,所以编译器能够在一开始就推断出 fli 的类型,对吧?那么f 是怎么推导出来的呢?我正在查看与类型推断相关的资源以了解实际情况,但如果您可以通过简单易懂地解释为什么它首先失败来编辑您的答案,那就太好了。
猜你喜欢
  • 2022-10-25
  • 1970-01-01
  • 2015-11-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-29
  • 2011-03-14
相关资源
最近更新 更多