简化单个向量的 std::transform
Simplifying std::transform for single vector
我想编写一个简单的函数来简化 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 [...]
您似乎在使用 lambda 作为参数; lambda 可以转换为 std::function
,但在 template argument deduction 中不会考虑隐式转换,这就是它失败的原因。
Type deduction does not consider implicit conversions (other than type adjustments listed above): that's the job for overload resolution, which happens later.
您可以在传递 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);
}
你过度约束了两个参数,并尝试对第二个参数同时使用模板推导和隐式转换,这是行不通的。放弃它,并可选择使用 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
,就像标准库算法一样。
另一种使用 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>&)>&);
我想编写一个简单的函数来简化 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 [...]
您似乎在使用 lambda 作为参数; lambda 可以转换为 std::function
,但在 template argument deduction 中不会考虑隐式转换,这就是它失败的原因。
Type deduction does not consider implicit conversions (other than type adjustments listed above): that's the job for overload resolution, which happens later.
您可以在传递 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);
}
你过度约束了两个参数,并尝试对第二个参数同时使用模板推导和隐式转换,这是行不通的。放弃它,并可选择使用 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
,就像标准库算法一样。
另一种使用 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>&)>&);