g ++无法推断功能映射实现的模板类型

时间:2015-08-08 13:33:47

标签: c++ c++11 lambda functional-programming

作为一个练习(请注意我知道std :: transform),我正在尝试实现通常在函数式语言(如C ++中的Haskell)中找到的map函数。这是我的代码:

#include <iostream>
#include <vector>
#include <functional>

template<typename A, typename B>
std::vector<B> functional_map (std::function<B(A)> func, std::vector<A> v)
{
    std::vector<B> result(v.size());
    for(int i = 0; i < v.size(); ++i) {
        result[i] = func(v[i]);
    }
    return result;
}

尽管如此,当这样调用时,编译器无法正确推断functional_map的模板类型:

int square (int x) {return x*x;}

int main()
{
    std::vector<int> v = {1,2,3,4,5,6,7,8,9,10};
    std::vector<int> v2 = functional_map(square, v);
    for (int y : v2) {
        std::cout << y << " ";
    }
}

这是G ++生成的错误:

functional_cpp.cpp: In function ‘int main()’:
functional_cpp.cpp:18:35: error: no matching function for call to ‘functional_map(int (&)(int), std::vector<int>&)’
     vector<int> v2 = functional_map(square, v);
                                   ^
functional_cpp.cpp:6:44: note: candidate: template<class A, class B> std::vector<B> functional_map(std::function<B(A)>, std::vector<A>)
 template<typename A, typename B> vector<B> functional_map (function<B(A)> func, vector<A> v) {
                                            ^
functional_cpp.cpp:6:44: note:   template argument deduction/substitution failed:
functional_cpp.cpp:18:35: note:   mismatched types ‘std::function<B(A)>’ and ‘int (*)(int)’
     vector<int> v2 = functional_map(square, v);

显然,g ++无法匹配std::function类型的常规函数​​指针,这样就可以为C ++中的所有函数进行一致的类型化。请注意,使用lambda更改square也会导致编译失败(但匹配的类型与nt (&)(int)lambda(int)的更改匹配。

话虽如此,将functional_map更改为functional_map<int, int>已成功编译并执行正确的结果。

为什么会这样?我如何修复我的实现,以便编译器推断模板类型?

编辑为了避免与std::map混淆,正如评论中所建议的那样,我在所有问题中都将“地图”更改为“functional_map”。

2 个答案:

答案 0 :(得分:2)

一个选项是获取任何可调用的函数对象并推断其结果类型:

#include <type_traits>

template <typename F, typename A,
          typename B = typename std::decay<typename std::result_of<F&(typename std::vector<A>::const_reference)>::type>::type>
std::vector<B> functional_map(F func, const std::vector<A>& v)
{
    std::vector<B> result(v.size());
    for (int i = 0; i < (int)v.size(); ++i)
    {
        result[i] = func(v[i]);
    }
    return result;
}

DEMO 1

std::result_of<F(Args...)>是一种类型特征,它利用std::declval<T>()函数和decltype()说明符的组合来推导类型为{{1}的函数对象的结果类型使用类型F的参数调用。也就是说,

Args...

相当于:

typename std::result_of<F&(typename std::vector<A>::const_reference)>::type

与:

相同
decltype(std::declval<F&>()(std::declval<typename std::vector<A>::const_reference>()))

您不需要为类型删除付费,但您仍然可以获得decltype(func(v[i])) 类型。

通过std::decay<T>类型保证它可以存储在向量中(如果函数对象返回引用等)。

或者,您可以将其声明为:

B

DEMO 2

或多或少相同。

答案 1 :(得分:1)

模板参数推导不考虑用户定义的转换。

自己进行转换:

vector<int> v2 = functional_map(std::function<int(int)>(square), v);