【问题标题】:Simplifying std::transform for single vector为单个向量简化 std::transform
【发布时间】:2018-10-20 11:20:17
【问题描述】:

我想编写一个简单的函数来简化 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 [...]

【问题讨论】:

  • @songyuanyao 我得到error: no matching function for call to 'transform'note: candidate template ignored: could not match 'function&lt;type-parameter-0-0 (const type-parameter-0-0 &amp;)&gt;' against '(lambda at [...]

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


【解决方案1】:

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

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

您可以在传递 lambda 时显式使用static_cast 将其转换为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);
}

【讨论】:

  • 现在工作。谢谢!
【解决方案2】:

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

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>&)>&);

【讨论】:

    【解决方案3】:

    您对两个参数都进行了过度约束,并尝试同时对第二个参数使用模板推导和隐式转换,这是行不通的。免除这一点,并选择性地使用 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::ref 传递std::reference_wrapper,就像标准库算法一样。

    【讨论】:

      猜你喜欢
      • 2013-02-07
      • 2016-03-01
      • 2017-01-16
      • 2020-03-22
      • 2021-09-22
      • 1970-01-01
      • 1970-01-01
      • 2011-08-08
      • 2014-02-27
      相关资源
      最近更新 更多