【问题标题】:Adding a map function to a vector in C++11在 C++11 中向向量添加映射函数
【发布时间】:2013-09-19 13:39:50
【问题描述】:

我有一个自定义向量类,它的所有意图和目的都类似于 std::vector。我想添加一个简单的地图功能:

template <class T> class Vector
{
public:
    template<class mapFunction> Vector<typename mapFunction::result_type> map(mapFunction function)
    {
        Vector<mapFunction::result_type> result(_Length);
        for(UINT i = 0; i < _Length; i++)
        {
           result[i] = function(_Data[i]);
        }
        return result;
    }
    ...
}

用法:

Vector<int> v(5);
for(int i = 0; i < 5; i++) v[i] = i;
auto mappedVector = v.map(function<double(int)>([](int a) { return a * 2.0; }));

这可行,但我试图避免将 lambda 表达式强制转换为 std::function。理想情况下它只是v.map([](int a) { return a * 2.0; })); 我意识到我可能可以编写一个类似于“make_pair”的“make_function”来避免需要模板参数,但是你仍然需要转换所有的 lambdas。

我将其转换为std::function,因为我不知道如何从原始 lambda 类型中提取返回类型;因此我使用std::function::result_type

我认为以下方法会起作用,但它不起作用——编译器只是抱怨它无法推断出“returnType”的模板参数:

template<class mapFunction, class returnType> Vector<returnType> Map2(mapFunction function)
{
    Vector<returnType> result(_Length);
    for(UINT i = 0; i < _Length; i++)
    {
        result[i] = function(_Data[i]);
    }
    return result;
}

我意识到std::transform 可以做到这一点(我可以很容易地用对std::transform 的调用来替换地图的主体),但我的问题实际上在于指定模板参数的正确方法。

【问题讨论】:

  • insted of lambda 尝试在类中传递一个自定义函子,其中定义了“result_type”类型..??
  • decltype(function(declval&lt;T&gt;())) 代替 mapFunction::result_type,也许?
  • 标准库中已经有一个具有相同功能的免费函数:std::transform(source.begin(), source.end(), std::back_inserter(target), my_function);
  • _Length_Data 是 C++ 中的保留标识符。

标签: c++ c++11


【解决方案1】:

首先,不要对这类问题使用std::function


我先给你举个例子,然后我会做一个简短的解释。请注意,我使用std::vector 来存储数据并提供功能,因为我真的不想自己实现整个Vector 类;)。

LIVE WORKING CODE

#include <iostream>
#include <vector>

//                /---------------------------------------------------------\
//                |                                                    //   |
template<typename T>                                                   //   |
class Vector {                                                         //   |
public:                                                                //   |
    std::vector<T> data;                                               //   |
                                                                       //   |
    template<class mapFunction>                                        //   |
    // Below: use C++11 trailing return type                                |
    auto map(mapFunction function) -> Vector<decltype(function(std::declval<T>()))>
    //                                       |                                   |
    {   //                                   |                                   |
        //                                   \-----------------------------------/
        //                                          |
        //                                          |
        //                 /-----------------------------------\
        //                 |                                   |
        using ReturnType = decltype(function(std::declval<T>()));

        Vector<ReturnType> result;

        auto size = data.size(); 
        result.data.reserve(size);

        for(std::size_t i = 0; i < size; i++)
        {
           result.data.push_back(function(data[i]));
        }

        return result;
    }
};

int main() {
    Vector<int> v;
    for(int i = 0; i < 10; ++i) {
        v.data.push_back(i);
    }

    auto newV = v.map([](int i) -> float {
        return (i * 2.0f) + 0.5f;       // Multiply by 2 and add 0.5
    });

    for(auto e : newV.data) {
        std::cout << e << std::endl;
    }
}

首先,它使用 C++11 的尾随返回类型特性。之所以需要这样做,是因为我们需要引用参数functiondecltype(function(std::declval&lt;T&gt;())) 部分是有趣的部分。在那,我们基本上是问编译器

“给定 T 类型的参数值,function 的返回类型是什么?”

然后编译器给出返回类型,这就是我们给结果Vector的第一个参数。

后面的部分与你的本质相同,尽管我为了正确和优雅而对其进行了修改。

请注意,在 C++14 中,您可以删除尾随返回类型,然后就这样做

template<class mapFunction>
auto map(mapFunction function) {
   using ReturnType = decltype(function(std::declval<T>()));
   Vector<ReturnType> result;

   ...

   return result;
}

【讨论】:

  • +1 花时间不仅提供了解决方案,还绘制了所有的 ASCII 艺术图以将各个部分链接在一起!
  • 我很好奇你为什么提到不使用 std::function 来解决这些类型的问题。
猜你喜欢
  • 2015-08-21
  • 1970-01-01
  • 2023-04-06
  • 2012-08-04
  • 1970-01-01
  • 2011-12-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多