已知参数的模板推导失败

时间:2016-07-12 15:53:37

标签: c++ templates c++11 lambda

考虑以下代码

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推导出模板参数?

2 个答案:

答案 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);
}

Live Demo