考虑以下代码
template<typename T>
T modify(const T& item, std::function<T(const T&)> fn)
{
return fn(item);
}
尝试将其用作modify(5, [](const int& i){return 10*i;});
时,无法使用
无法从
推断'std::function<T(const T &)>
lambda
的模板参数
我知道编译器不能从lambda中推导出T
,因为lambda不是std::function
,而是T
已经从5
推断出来了吗?
我可以使用
克服它template<typename T, typename F>
T modify(const T& item, const F& functor)
{
return functor(item);
}
之前的例子编译,但在我看来不太直观。有没有办法让函数参数保持std::function
并自动从item
推导出模板参数?
答案 0 :(得分:4)
您基本上想要做的是防止扣除发生。如果发生模板推导,它将失败(因为lambda不是std::function<>
- 从第一个参数中推导出T
并不重要,推导必须在每个参数中成功推论上下文)。防止演绎的方法是将整个参数保留在非推导的上下文中,最简单的方法是将类型抛出到嵌套名称说明符中。我们创建了这样一个类型的包装器:
template <class T> struct non_deduce { using type = T; };
template <class T> using non_deduce_t = typename non_deduce<T>::type;
然后将类型包装在其中:
template<typename T>
void foo(const T& item, std::function<void(T)> f);
template<typename T>
void bar(const T& item, non_deduce_t<std::function<void(T)>> f);
foo(4, [](int ){} ); // error
bar(4, [](int ){} ); // ok, we deduce T from item as int,
// which makes f of type std::function<void(int)>
但请注意:
template <typename T, typename F>
void quux(const T&, F );
实际上不是那么可读,而且性能更高。
答案 1 :(得分:3)
您可以使用identity
技巧执行此操作,如下所示:
template <typename T>
struct identity {
typedef T type;
};
template<typename T>
T modify(const T& item, typename identity<std::function<T(const T&)>>::type fn) {
return fn(item);
}