【问题标题】:Template functor cannot deduce reference type模板函子不能推断引用类型
【发布时间】:2010-03-29 15:57:16
【问题描述】:

我有一个函子 f,它接受一个函数 func 和一个与 func 相同类型的参数 t。由于编译错误,我无法将 g 传递给 f(没有用于调用 f(int&, void (&)(int&)) 的匹配函数)。如果 g 将采用非引用参数 g(int s),则编译完成。或者如果我手动指定模板参数f<int&>(i, g),编译也完成。

template<typename T>
void f(T t, void (*func)(T)) {}

void g(int& s) {}

int main(int, char*[])
{
    int i = 7;

    f(i, g); // compilation error here

    return 0;
}

我怎样才能让扣除起作用?

【问题讨论】:

  • 请花时间学习输入代码块(大和内联)。只有在我编辑了您的问题之后,您才明显知道我在答案中提到的明确传递。

标签: c++ templates reference functor


【解决方案1】:

你可以这样调用函数:

f<int&>(i, g);

但现在我也将通过引用传递。

一般来说,我也会将函数设为模板类型:

template <typename T, typename F>
void f(T t, F func) 
{ 
    func(t); //e.g
}

【讨论】:

    【解决方案2】:

    我认为你需要:

    void f(T t, void (*func)(T&)) {}
    

    或:

    void g(int s) {}
    

    但我更喜欢:

    template<typename T, typename T2> 
    void f(T t, T2 func) {}
    

    因为这适用于函数和仿函数。

    【讨论】:

      【解决方案3】:

      问题是,如果模板中的一个函数参数在推导开始之前不是引用类型,则该参数将永远不会推导出为引用类型。所以在左边的推导中,T 产生int,但在右边的推导中,T 产生int&amp;。那是不匹配的,编译器会抱怨。

      最好是让函数参数和函数指针的参数类型一致:

      template<typename T> struct identity { typedef T type; };
      
      template<typename T>
      void f(typename identity<T>::type t, void (*func)(T)) {}
      

      通过使用identity&lt;T&gt;::type,您可以禁用左侧的扣除。一旦在右侧确定了TT 就会被替换到左侧并产生最终的参数类型。

      有人提议将右侧作为模板参数——这是一件好事,因为它可以接受带有operator() 重载的函数对象。但是您随后面临必须知道它是否需要参考的问题。为了解决这个问题,boostreference_wrapper(顺便说一下,boost 也有上面的identity 模板)。

      template<typename T, typename F>
      void f(T t, F func) {}
      

      现在,如果你想传递引用而不是副本,你可以这样做

      int i;
      f(boost::ref(i), some_function);
      

      ref 返回一个可隐式转换为T&amp; 的r​​eference_wrapper 对象。因此,如果您调用func(t)t 会自动转换为目标引用。如果不想传递引用,直接传递i即可。

      【讨论】:

      • 嗯,identity 版本也与 const int i 不同。
      • @gf 你能举个例子吗?我不确定你的意思是什么以及它在哪里中断。
      • 抱歉 - 在 OP 示例中使用 const int i 时,i 无法传递给生成的 f(int&amp;,void(*)(int&amp;))
      • @gf 我认为这在很大程度上是预期的行为。假设f 将仅通过其参数接受它。但这不会有任何好处,因为当它调用func(t) 时我们仍然会得到一个错误。 f 很好地拒绝了这一点,除非我错过了什么:)
      • 呃,是的……我现在要补觉了。很抱歉造成混乱:)
      【解决方案4】:
      template<typename T>
      void f(T t, void (*func)(T)) {}
      

      这里的关键是你在两个参数中都使用了T。这意味着类型必须完全匹配。

      void g(int& s) {}
      
      int i = 7;
      f(i, g);
      

      在您的代码中,您将一个int 和一个采用int&amp; 的函数传递给f()。这些是不同 类型,但您的f 模板需要两个相同 类型。正如其他人所建议的,最简单的解决方法是将函数也设为模板。

      template <typename T, typename F>
      void f(T t, F func) 
      { 
          func(t);
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-02-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-09-12
        • 2016-11-05
        相关资源
        最近更新 更多