【问题标题】:Passing functor with templated parameters to template function将带有模板参数的仿函数传递给模板函数
【发布时间】:2019-01-12 02:18:43
【问题描述】:

我正在编写一个以仿函数为参数的函数。仿函数的调用运算符的参数是模板化的。我正在尝试做的一个非常简化的版本是:

#include <iostream>
#include <functional>
#include <array>

template <const size_t N>
using CVec = std::array<double,N>;

template<const size_t N>
using ode_fun = std::function<CVec<N>(const CVec<N>&)>;

template<const size_t N>
void step( const CVec<N>& x, ode_fun<N> sys)
{
  sys(x);
}

struct foo_t
{
  CVec<2>  operator()( const CVec<2>& x_in)
  {
    CVec<2> xdot;

    std::cout << "x_in: [" << x_in[0] << ", " << x_in[1] << "]\n";

    return xdot;
  }
  CVec<2> x;
};

int main()
{
  foo_t foo;
  foo.x[0] = -.5;
  foo.x[1] = 1.0f;

  CVec<2> x;
  x[0] = 12.0;
  x[1] = 23.2;

  step(x, foo);
}

但是在编译时,我得到了这个错误:

temp_arg_subs_fail.cpp: In function ‘int main()’:
temp_arg_subs_fail.cpp:42:14: error: no matching function for call to ‘step(CVec<2>&, foo_t&)’
   step(x, foo);
              ^
temp_arg_subs_fail.cpp:12:6: note: candidate: template<long unsigned int N> void step(CVec<N>&, ode_fun<N>)
 void step( const CVec<N>& x, ode_fun<N> sys)
      ^~~~
temp_arg_subs_fail.cpp:12:6: note:   template argument deduction/substitution failed:
temp_arg_subs_fail.cpp:42:14: note:   ‘foo_t’ is not derived from ‘std::function<std::array<double, N>(const std::array<double, N>&)>’
   step(x, foo);
              ^

但这是可行的:

#include <functional>
#include <iostream>

using my_fn = std::function<int(int, int)>;

void summer(int x, int y, my_fn fn)
{
  std::cout << "summer: " << fn(x,y) << std::endl;
}

struct foo_t
{
  int operator()(int x, int y)
  {
    return x + y + z;
  }    
  int z = 0;    
};

int main ()
{    
  foo_t foo;
  foo.z = 5;    

  summer(3,4,foo);

  return 0;
}

基本上,我能看出两者之间的唯一区别是一个是模板化的,另一个不是。是因为第一个sn-p中的step函数只是一个模板,没有实例化还是别的什么?

【问题讨论】:

    标签: c++11 templates c++14 functor template-argument-deduction


    【解决方案1】:

    问题在于step() 需要一个ode_fun&lt;N&gt; 对象作为第二个参数(即std::function&lt;std::array&lt;double, N&gt;(std::array&lt;double, N&gt; const &amp;)&gt;),而N 将被推导出来。

    但是如果你传递foo,那是一个foo_t对象,可以转换为ode_fun&lt;2&gt;,但是(这就是重点)不是ode_fun&lt;2&gt;对象,编译器无法推断出N 的值。

    您可以通过两种明显的方式解决问题。

    (1) 将ode_fun&lt;2&gt; 对象传递给step()

    ode_fun<2>  foo2 { foo };
    
    step(x, foo2);
    

    (2) 或者在step() 中推导出一个简单类型F(作为“函数”),所以所有函数都是可推导出的

    template<const size_t N, typename F>
    void step( const CVec<N>& x, F sys)
    {
      sys(x);
    }
    

    是不是因为第一个sn-p中的step函数只是一个模板,没有实例化还是别的什么?

    没错。

    在您的非模板示例中,summer() 收到 std::function&lt;int(int, int)&gt;

    没有什么是推论出来的,传递一个foo_t对象,它不是std::function&lt;int(int, int)&gt;,但可以转换成它,编译器将foo转换成std::function&lt;int(int, int)&gt;

    【讨论】:

    • 感谢您的回答——在询问之前我尝试了解决方案 (2),效果非常好。我还尝试了解决方案(1),方法是将 foo 作为std::function&lt;odefun&lt;2&gt; &gt;(foo) 传递给不起作用的step 函数(现在看起来很明显为什么)。用简单的ode_fun&lt;2&gt;(foo) 包装它并将其传递给step 效果很好。
    猜你喜欢
    • 1970-01-01
    • 2011-11-15
    • 1970-01-01
    • 2011-08-26
    • 1970-01-01
    • 2017-12-25
    • 1970-01-01
    • 2016-05-17
    • 1970-01-01
    相关资源
    最近更新 更多