首页 > 解决方案 > 将列表映射到不同的类型

问题描述

我正在尝试创建一个List类,主要是因为我想自己实现一些向量不存在的方法。其中之一是一个map()函数,您可以在其中将 lambda 作为参数传递,并且该方法返回一个新List的,其中旧列表中的每个值都已传递给该函数。

我遇到的问题是获取方法来处理返回List具有不同类型的特征。例如:

List<Option<int>> y;
y.append(option(1));
y.append(option(2));
y.append(option(3)); 
//y is [Option(1), Option(2), Option(3)]

List<int> z = y.map([](Option<int> o) {return o.get();});

//z should be [1,2,3]

函数在map()其当前状态下定义为:

template<typename S>
List<S> map(S (* function)(T)) {
    List<S> output;     
    for (int i = 0; i < size(); i++) {
        output.append(function((*this)[i]));
    }
    return output;
}

问题是上面似乎不允许我传入一个 lambda,只能传入一个先前定义的函数,这违背了该方法方便的目的。我可以让它接受 lambda 的唯一方法是将函数定义为:

template<typename S, typename R>
List<S> map(R function) {
    List<S> output;  
    for (int i = 0; i < size(); i++) {
        output.append(function((*this)[i]));
    }
    return output;
}

但这导致了一个不同的问题,它说:

没有函数模板 'List<T>::map[with T=Option<int>]' 的实例与参数列表匹配

是否有特定的解决方法,或者我每次调用函数时都必须声明map()函数?

标签: c++listdictionarytemplateslambda

解决方案


使用decltype. 在您的定义中,您希望使用函数返回的内容来确定output列表返回值的类型。所以你可以做这样的事情:

template<typename R>
auto map(R function) {
    List<std::decay_t<decltype(function(operator[](0)))>> output;
    for(int i = 0; i < size(); i++) output.append(function(operator[](i)));
    return output;
}

列表元素的类型是function在 的元素上调用时返回的任何内容this。将std::decay_t您无法存储的类型(引用、cv 限定类型、数组等)转换为您可以存储的类型(分别为非引用、非限定类型、指针等)。

使用 可以实现更强大的结果std::invoke_result,它允许您将函数调用替换为std::invoke

template<typename T>
struct List {          // Your list class, we need the T
    template<typename R>
    auto map(R function) {
        List<std::decay_t<std::invoke_result_t<R, T&>>> output; // assuming that accesses give references
        for(int i = 0; i < size(); i++) output.append(std::invoke(function, operator[](i)));
        return output;
    }
};

结果是现在您还可以使用map指向列表中成员的指针之类的东西。

神螺栓


推荐阅读