2013-10-24 73 views
4

假设我想在C++中实现一个通用的高阶Map函数。 Map应带一个容器和一个转换函数,并返回一个相同类型的容器,但可能使用不同类型的项目。模板类型的约束

让我们vector例如:

template <typename InT, typename OutT, typename Tr> 
vector<OutT> Map(vector<InT> cont, Tr tr) 
{ 
    OutCont out(cont.size()); 
    auto oit = out.begin(); 
    for (auto it = cont.cbegin(); it != cont.cend(); ++it, ++ot) 
    { 
     *oit = tr(*it); 
    } 
} 

,我想用这样的:

vector<int> v(10); 
std::iota(v.begin(), v.end(), 0); 
auto x = Map(v, [](int x) -> int {return x * 2;}); 

这种失败在VC++ 2012,给我下面的错误:

error C2783: 'std::vector<OutT> Map(std::vector<_Ty>,Tr)' : could not deduce template argument for 'OutT' 

在我看来,编译器具有所有必要的信息,因为我明确定义lambda中的返回类型。有没有解决的办法?

上述示例使用vector。有没有办法使用泛型类型,以便输入和输出类型相同?例如,如果我有一个输入容器定义为vector<string>和转换函数tr(string a) -> int,那么我的目标是让编译器找出输出类型为vector<int>。下面是伪代码为我想要实现:输出类型推断

template <typename InT, typename Tr> 
auto Map(std::vector<InT> cont, Tr tr) -> std::vector<decltype(tr(cont[0]))> 
{ 
    std::vector<decltype(tr(cont[0]))> out(cont.size()); 
    auto oit = out.begin(); 
    for (auto it = cont.cbegin(); it != cont.cend(); ++it, ++oit) 
    { 
     *oit = tr(*it); 
    } 
    return out; 
} 

template <typename Cont<InT>, typename Cont<OutT>, typename Tr<InT, OutT>> 
Cont<OutT> Map(Cont<InT> cont, Tr<InT, OutT> tr) 
{ 
    // Implementation 
} 
+2

无关,但命名您的函数'map'比较混乱,给出'std :: map'。 – juanchopanza

+2

函数式编程'map' =='std :: transform'。迭代器真的可以让你在C++中通过容器进行泛型编程:使用它们。 – Yuushi

+0

谢谢。我将它改为'Map'。应该消除混淆。 – Max

回答

4

你可能喜欢写东西。

[编辑] 对于具有多个容器更通用的功能:

template <template<typename, typename...> class Container, typename InT, typename Tr, typename... Args> 
auto Map(const Container<InT, Args...>& cont, Tr tr) -> Container<decltype(tr(cont[0])), Args...> 
{ 
    Container<decltype(tr(cont[0])), Args...> out(cont.size()); 
    auto oit = out.begin(); 
    for (auto it = cont.cbegin(); it != cont.cend(); ++it, ++oit) 
    { 
     *oit = tr(*it); 
    } 
    return out; 
} 

通知的typename...必要的,因为std::vector也可以采取分配

+0

谢谢。那是我需要的。仍然有一个问题,这是为了一个泛型类型,而不仅仅是向量。 – Max