简化单个向量的std :: transform

时间:2018-10-20 11:20:17

标签: c++ c++11 templates implicit-conversion argument-deduction

我想编写一个简单的函数来简化std::transform以便在单个向量上进行转换。

到目前为止我所拥有的:

template<typename T>
void transform(std::vector<T> &vec, const std::function<T(const T &)> &fun) {
  std::transform(std::begin(vec), std::end(vec), std::begin(vec), fun);
}

现在,当我想使用此功能时,我可以编写,例如:

transform<int>(vec, my_function);

但是我更愿意使用

transform(vec, my_function);

有没有办法调整我的代码以自动推断类型?

错误:

no matching function for call to 'transform' and note: candidate template ignored:
could not match 'function<type-parameter-0-0 (const type-parameter-0-0 &)>' 
against '(lambda at [...]

3 个答案:

答案 0 :(得分:3)

似乎您正在使用lambda作为参数; lambda可以转换为std::function,但是在template argument deduction中不会考虑隐式转换,这就是失败的原因。

  

类型推导不考虑隐式转换(上面列出的类型调整除外):这是超载解析的工作,稍后会发生。

您可以在传递时显式使用static_cast将lambda转换为std::function,或停止使用std::function。例如

template<typename T, typename F>
void transform(std::vector<T> &vec, F fun) {
  std::transform(std::begin(vec), std::end(vec), std::begin(vec), fun);
}

答案 1 :(得分:1)

如果出于某种原因需要使用std::function参数,另一种方法是通过将T移到非推导上下文中来禁用其中的T类型推导: / p>

template<typename T>
struct Identity { using Type = T; };

template<typename T>
using Id = typename Identity<T>::Type;

template<typename T>
void transform(std::vector<T>&, const std::function<Id<T>(const Id<T>&)>&);

答案 2 :(得分:0)

您过度约束了两个参数,并尝试同时使用template-deduction和隐式转换作为第二个参数,这是行不通的。无需这样做,可以选择使用SFINAE,使事情正常,高效和灵活地运行:

using std::begin;
using std::end;

template <class Range, class F>
auto transform(Range&& range, F f)
noexcept(noexcept(std::transform(begin(range), end(range), begin(range), f)))
-> decltype(std::transform(begin(range), end(range), begin(range), f))
{ return std::transform(begin(range), end(range), begin(range), f); }

是,复制了功能对象。如果您不希望这样做,只需使用std::reference_wrapper传递std::ref即可,就像标准库算法一样。