在尝试制作" map"时,无法推断出模板参数。功能

时间:2014-08-19 17:14:12

标签: c++ templates c++11

我想在C ++中创建一个“map”函数,它接受一个函数和一个容器并返回该容器,但是由函数返回的类型元素,这些元素应该是将函数应用于元素的结果容器参数。

例如,我们应该能够做到这一点:

map([](int i){return float(i + 1);}, vector<int> {1, 2, 3});  // vector<float> {2.0, 3.0, 4.0}

这是我尝试实现它,但看起来我并不完全理解模板编程: http://ideone.com/zMYCVw

#include <iostream>
#include <functional>
#include <string>
#include <list>
#include <vector>

template <
    typename FunctionT,
    template <typename> class ContainerT,
    typename ElemT,
    class FunctionResultT = typename std::result_of<FunctionT>
>
ContainerT<FunctionResultT> map(
    FunctionT func,
    const ContainerT<ElemT>& container
){
    ContainerT<FunctionResultT> resultContainer;
    for (const auto& elem : container){
        resultContainer.push_back(func(elem));
    }
    return resultContainer;
}


template <typename T>
T increaseByOne(const T& number){
    return number + 1;
}

template <typename T>
std::string numberToString(const T& number){
    return std::to_string(number);
}


int main(){
    const auto theList = std::list<float> {1.0, 2.0, 3.0, 4.0, 5.0};

    for (const auto& ele : map(numberToString, map(increaseByOne, theList))){
        std::cout << ele << std::endl;
    }
}

这是编译器的错误:

file.cpp:39:48: error: no matching function for call to 'map'
    for (const auto& ele : map(numberToString, map(increaseByOne, theList))){
                                           ^~~
file.cpp:13:29: note: candidate template ignored: couldn't infer template argument 'FunctionT'
ContainerT<FunctionResultT> map(
                        ^
1 error generated.

2 个答案:

答案 0 :(得分:3)

我发现了一些导致问题的事情。这是我发现的列表:

  • 函数模板表示无限过载集。当您将函数作为参数传递时,需要知道函数的类型。这意味着需要明确指定模板参数。也就是说,这些需要改变:

    map(numberToString, map(increaseByOne, theList)
    //  ^^^^^^^^^^^^^^      ^^^^^^^^^^^^^
    

    对此:

    map(numberToString<float>, map(increaseByOne<float>, theList)
    //                ^^^^^^^                   ^^^^^^^
    
  • std::list需要多个模板参数。其余的都是默认的。将模板参数定义为:

    template<typename> class ContainerT,
    

    这意味着ContainerT只能接受单个模板参数。当编译器发现您试图从std::list的实例推断出这种类型时,它会发现模板参数的数量不匹配。然后类型扣除失败。 C ++ 11具有可变参数包,您可以使用它们使ContainerT接受任意数量的模板参数:

    template<typename...> class ContainerT,
    
  • 最后,您没有为type提供FunctionResultT。你可以在这里这样做:

    class FunctionResultT = typename std::result_of<FunctionT>::type
    //                                                        ^^^^^^
    

    但请注意,这将失败,因为std::result_of是一个模板,如果其模板参数是仿函数,则只提供::type成员。这基本上意味着如果它是一个具有重载operator()成员函数的类。

    您可以std::result_of默认为函数调用的类型,而不是使用FunctionResultT。像这样:

    class FunctionResultT = decltype(std::declval<FunctionT>()(std::declval<ElemT>()));
    

现在这是我所做的更改的结果:

template <
    typename FunctionT,
    template <typename...> class ContainerT,
    typename ElemT,
    class FunctionResultT = decltype(std::declval<FunctionT>()(std::declval<ElemT>()))
>

答案 1 :(得分:0)

template<class OutputContainer, class InputContainer, typename Fn>
OutputContainer map(Fn fn, InputContainer input_container){
    OutputContainer output;
    for(auto&i:input_container)
        output.push_back(fn(i));
    return output;
}