编译器不推导出模板参数(map std :: vector - > std :: vector)

时间:2014-10-30 23:25:53

标签: c++ templates c++11 vector std

我有以下模板。

template<typename T, typename U>
std::vector<U> map(const std::vector<T> &v, std::function<U(const T&)> f) {
    std::vector<U> res;
    res.reserve(v.size());
    std::transform(std::begin(v), std::end(v), std::end(res), f);
    return res;
}

当我在我的代码中使用它时,我指定了模板参数。为什么编译器无法为我推断出这个?如何更改模板定义以使其工作?

vector<int> numbers = { 1, 3, 5 };

// vector<string> strings = map(numbers, [] (int x) { return string(x,'X'); });

vector<string> strings = map<int, string>(numbers, [] (int x) { return string(x,'X'); });

可运行代码:http://ideone.com/FjGnxd

此问题中的原始代码来自此处:The std::transform-like function that returns transformed container

1 个答案:

答案 0 :(得分:17)

您的函数需要std::function参数,但您使用lambda表达式调用它。两者不是同一类型。 lambda 可转换std::function,但模板参数推导需要完全匹配,并且不考虑用户定义的转换。因此扣除失败。

如果您实际将std::function传递给map(),则可以使用扣除。

std::function<string(int const&)> fn = [] (int x) { return string(x,'X'); };
vector<string> strings = map(numbers, fn);

Live demo


避免必须指定模板参数的一种可能的解决方法是修改函数以接受任何类型的可调用而不是std::function对象。

template<typename T, typename Func>
std::vector<typename std::result_of<Func(T)>::type>
    map(const std::vector<T> &v, Func f) {
        // ...
    }

同一想法的另一个版本,使用decltypedeclval代替result_of

template<typename T, typename Func>
std::vector<decltype(std::declval<Func>()(std::declval<T>()))>
    map(const std::vector<T> &v, Func f) {
        // ...
    }

最后,使用尾随返回类型

template<typename T, typename Func>
auto map(const std::vector<T> &v, Func f) 
  -> std::vector<decltype(f(v[0]))> {
        // ...
    }

Live demo