【发布时间】:2014-10-23 01:20:29
【问题描述】:
作为我的第一个模板元程序,我正在尝试编写一个将输入向量转换为输出向量的函数。
例如,我想要
vector<int> v={1,2,3};
auto w=v_transform(v,[](int x){return (float)(x*2)})
将 w 设置为三个浮点数的向量,{2.0, 4.0, 6.0}。
我从这个 stackoverflow 问题开始,The std::transform-like function that returns transformed container,它解决了转换任意容器这一更难的问题。
我现在有两个解决方案:
一个解决方案,
v_transform_doesntwork不起作用,但我不知道为什么(我自己写的)。一个解决方案,
v_transform可行,但我不知道为什么(基于 Michael Urman 对上述问题的回答)
我正在寻找简单的解释或指向解释正在发生的事情的文献。
这里有两个解决方案,v_transform_doesntwork 和 v_transform:
#include <type_traits>
#include <vector>
using namespace std;
template<typename T, typename Functor,
typename U=typename std::result_of<Functor(T)>::type>
vector<U> v_transform(const std::vector<T> &v, Functor&& f){
vector<U>ret;
for(const auto & e:v)
ret.push_back(f(e));
return ret;
}
template<typename T, typename U>
vector<U> v_transform_doesntwork(const std::vector<T> &v, U(*f)(const T &)){
vector<U>ret;
for(const auto & e:v)
ret.push_back(f(e));
return ret;
}
float foo(const int & i){
return (float)(i+1);
}
int main(){
vector<int>v{1,2,3,4,5};
auto w=v_transform(v,foo);
auto z=v_transform(v,[](const int &x){return (float)(x*2);});
auto zz=v_transform(v,[](int x){return (float)(x*3);});
auto zzz=v_transform_doesntwork(v,[](const int &x){return (float)(x*2);});
}
问题 1:为什么对 v_transform_doesntwork 的调用无法编译? (它给出了一个匹配失败的模板错误,c++11。我在参数列表中尝试了大约 4 种“const”、“&”和“*”的排列,但似乎没有任何帮助。)
我更喜欢v_transform_doesntwork的实现,而不是v_transform的实现,因为它更简单,但它有一个不工作的小问题。
问题 2:为什么调用 v_transform 有效?我清楚地了解正在发生的事情,但我不明白为什么在定义 U 时需要所有类型名,我不明白这种定义模板参数的奇怪语法是如何在同一定义中稍后依赖的甚至允许,或者在所有指定的地方。我尝试在 cppreference 中查找“依赖类型名称”,但对这种语法一无所知。
进一步说明:我假设 v_transform 有效,因为它可以编译。如果在某些情况下它会失败或出现意外行为,请告诉我。
【问题讨论】:
-
闭包不是函数指针。它们可能对它们可转换,但这不是一回事。
-
那为什么不转换呢?
-
如果你可以依赖 C++11,看看 trailing-return-type 和
decltype。它们将使您的生活更轻松。 -
@kdog:要进行转换,您需要说明将其转换为哪种类型,但您没有这种情况,因为您选择要求模板参数推导。然后,参数推导也不会考虑用户定义的转换(如果您考虑一下,那将永远不会起作用)。
标签: c++ templates c++11 template-meta-programming