我想在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.
答案 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;
}