传递具有模板化返回类型的std :: function类型

时间:2016-03-19 17:08:35

标签: c++ c++11 std-function

我有一个功能

template<typename P = int_fast16_t, typename I>
std::vector<std::vector<P>> f(
    I xb, I xe, I yb, I ye,
    std::function<P(typename std::iterator_traits<I>::value_type,
                    typename std::iterator_traits<I>::value_type)> &&score_function,
    P ID = -1, P S = -1, P M = 1)

它需要两对迭代器和一个函数,它应该比较迭代器的value_type的两个元素,并返回一个类型为P的值。

这给了我一个错误

./h.hpp:47:32: note: candidate template ignored: could not match 'function<type-parameter-0-0 (typename iterator_traits<type-parameter-0-1>::value_type, typename iterator_traits<type-parameter-0-1>::value_type)>' against 'stringAlgorithms::scoring::plus_minus_one'
   std::vector<std::vector<P>> nw_score_matrix(I xb, I xe, I yb, I ye, 

现在,如果我将其更改为使用特定的返回类型P

template<typename P = int_fast16_t, typename I>
   std::vector<std::vector<P>> nw_score_matrix(I xb, I xe, I yb, I ye, std::function<int_fast16_t(typename std::iterator_traits<I>::value_type, typename std::iterator_traits<I>::value_type)> &&score_function, P ID = -1, P S = -1, P M = 1)

这个编译。

在这种情况下,函数plus_minus_one是

  struct plus_minus_one {
     template<typename T, typename R = int_fast16_t>
     R operator()(const T &x, const T &y) { return x == y ? 1 : -1; }
  };

并使用

传递
scoring::plus_minus_one matchScoring;

nw_score_matrix(x.begin(), x.end(), y.begin(), y.end(), matchScoring);

我意识到我可以在模板中声明一个typename F并使score_function成为

F &&score_function

但是我想确保如果某人创建了一个特定于某些类型的函数/ lambda,那么该函数将处理正确的类型。那么为什么声明不能编译?

编辑:找到完整示例https://github.com/meconlen/stringAlgorithms/tree/soq

3 个答案:

答案 0 :(得分:3)

要调用此功能,您需要实际给它一个<!doctype html> <html> <head> <style> a:not(.myimage):hover,a:not(.myimage):focus,.text-link:not(.myimage):hover,.text-link:not(.myimage):focus{ background: #551011; color: #8b6508; } </style> </head> <body> <a href="#">link</a> <a class="myimage" href="#"><img src='abc.png'></a> </body> </html>

std::function

否则,编译器的转换次数太多,无法确定您要执行的操作。

答案 1 :(得分:2)

简要说明。当你写:

P

然后P仍处于推断的上下文中,这意味着编译器将尝试根据参数表达式的类型推导出int,忽略默认值(std::function<float()> a; f(a); )。但是,类型推导仅推导类型,即参数表达式的类型必须与相应参数的类型匹配,以便编译器推导出缺少的类型模板参数

所以,一旦你调用下面的函数:

P

编译器会将float替换为char foo() { return {}; } f(&foo);

现在,如果你想传递,例如函数的地址:

P

编译器会抱怨它无法推断char(*)(),因为:

  1. 它仍处于推断的背景中。
  2. 参数的类型(std::function<P()>)与参数P的类型不匹配。
  3. 也就是说,编译器不知道std::function<P()>的签名中的char应该与函数指针的返回类型f<char>(&foo); 匹配。

    你可以说,明确强制类型:

    std::function

    但这并不灵活。

    您还可以将P置于非推断的上下文中,并在其他位置推导template <typename T> struct identity { using type = T; }; template <typename P> void f(typename identity<std::function<P()>>::type, P c) {} f(&foo, 'a'); // P will be deduced from the 'a' argument

    c

    但如果template <typename F> void f(F&& f) {} f(&foo); 默认且未在函数调用参数列表中指定,则无法工作。

    没有什么可以阻止你推断出参数表达式的确切类型:

    f

    如果您关心,您可以随时检查P返回的内容是否可转换为plus_minus_one,或者只读取该类型。

    在您的方案中,完全不相关类型(std::function)的实例作为operator()的实例传递,因此显然,推断失败。编译器不知道它必须查看它的std::function,并使用它的默认返回类型。

    Map<String, String> map = new HashMap<String, String>();{ map.put("Speed", speed.gettext.tostring()); map.put("date",currentdate()); } 本身就是一种类型橡皮擦,在您的情况下,您并不需要删除任何类型。

答案 2 :(得分:1)

根据Piotr Skotnicki提供的建议,我为您获得了以下可能的解决方案。您希望C ++推导出score_function本身的类型,而不是它的嵌套类型。但是,一旦您拥有该类型 - 让我们称之为F,您就可以手动检索所需内容。

这个帮助程序特征结构从代码中提取P给定的函数类型F(基本上是Piotr Skitnicki的评论)

template<typename F, typename I>
struct PP {
    typedef typename std::decay<typename std::result_of<
      F(typename std::iterator_traits<I>::value_type,
        typename std::iterator_traits<I>::value_type)
      >::type>::type type;
};

现在,通过此帮助,您可以将您的功能定义为:

template<typename I, typename F>
   std::vector<std::vector<typename PP<F,I>::type>>
     nw_score_matrix(I xb, I xe, I yb, I ye,
                     F &&score_function,
                     typename PP<F,I>::type ID = -1,
                     typename PP<F,I>::type S = -1,
                     typename PP<F,I>::type M = 1)
   {
       typedef typename PP<F,I>::type P;

       ....... your existing code ......
   }

...然后您可以在呼叫站点上调用该函数而不进行任何更改。特别是,您不需要将matchScoring转换为std::function对象。

我认为它符合您F可能是仿函数,std::function或lambda的要求 - 它应该适用于所有情况。