【问题标题】:In C++11, is it possible to wrap a template function in a std::function?在 C++11 中,是否可以将模板函数包装在 std::function 中?
【发布时间】:2015-03-12 15:27:47
【问题描述】:

如果我在 C++11 中有一个模板函数,那么是否可以将其包装在 std::function 中?

我的问题是这样的:

我有一个通用函数(比如 sum 函数),其中返回类型取决于参数的类型:

template <typename T>
auto sum(T const& a, T const& b) -> decltype(a+b)
{
    return a + b;
}

我想将它包装在 std:function 中以用于特定的参数类型(比如 int)。我正在尝试以下方法:

int main()
{
  std::function<int(int,int)> intsum = std::bind(static_cast<int(*)(int,int)>(&sum), std::placeholders::_1, std::placeholders::_2);
  auto mysum = intsum(2, 4);

  std::cout << mysum << std::endl;

  return 0;
}

但是编译上面的代码会报错:

error: invalid static_cast from type ‘<unresolved overloaded function type>’ to type ‘int (*)(int, int)

有什么方法可以实现我想要做的吗?

【问题讨论】:

  • 你试过sum&lt;int&gt;吗?
  • 模板函数不是函数。如果您使用正确的名称函数模板,则表明您还没有处理函数。

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


【解决方案1】:

您可以专门化模板并使用它:

std::function<int(int,int)> intsum = sum<int>;
auto mysum = intsum(2, 4);

std::cout << mysum << std::endl;

【讨论】:

    【解决方案2】:

    您不能将通用函数包装在 std::function 的特定实例中,这正是您所要求的。

    但是,您可以包装一个通用函数的完全指定的instance,这正是您的代码实际尝试做的事情:

    template <typename T>
    auto sum(T const& a, T const& b) -> decltype(a+b)
    {
      return a + b;
    }
    
    #include <functional>
    #include <iostream>
    
    int main()
    {
      std::function<int(int,int)> intsum =
        std::bind(sum<int>,
                  std::placeholders::_1, std::placeholders::_2);
      auto mysum = intsum(2, 4);
    
      std::cout << mysum << std::endl;
    }
    

    或者更简单

      std::function<int(int,int)> intsum = sum<int>;
    

    当然,如果你真的不需要包装它,只需:

      auto mysum = sum(2, 4);
    

    【讨论】:

      【解决方案3】:

      你的问题是类型错误。

      没有sum&lt;?&gt;int(int,int) 过载。所以当你static_cast&lt;int(*)(int,int)(sum)时,它会抱怨它无法进行转换。

      int(int const&amp;,int const&amp;) 过载。如果你 static_cast&lt;int(*)(int const&amp;, int const&amp;)&gt;(sum) 它会起作用。

      如果没有这样的重载指向,函数模板到函数指针的转换将不起作用。

      有三种方法是合理的。

      首先,转换为正确的类型。 static_cast&lt;int(*)(int const&amp;,int const&amp;)&gt;(sum).

      第二,明确专业化。 sum&lt;int&gt; 而不是 static_cast 表达式。

      三、创建重载集对象:

      struct sum_t{
        template<class...Args>
        auto operator()(Args&&...args)const
        -> decltype(sum(std::declval<Args>()...))
        {
          return sum(std::forward<Args>(args)...);
        }
      };
      static sum_t sum_os;
      

      并将static_cast&lt;int(*)(int,int)&gt;(sum) 替换为sum_os

      sum_os 可以传递给bindstd::function 或其他任何东西,并且重载决议推迟到调用代码。

      作为奖励,编译器比函数指针调用更容易优化。

      作为否定,完美的转发是不完美的。

      重载集的 C++14 版本是:

      [](auto&&...args)->
      decltype(sum(decltype(args)(args)...))
      { return sum(decltype(args)(args)...); }
      

      可以转成宏:

      #define OVERLOAD_SET(FUNC) \
        [](auto&&...args)-> \
        decltype(FUNC(decltype(args)(args)...)) \
        { return FUNC(decltype(args)(args)...); }
      

      这让您只需在使用时执行OVERLOAD_SET(sum),并传入整个重载集。

      【讨论】:

      • 为什么不在 C++14 lambda 版本中使用-&gt;decltype(auto)
      • @piotrs。 SFINAE 不适用于返回类型扣除。我希望能够询问电话是否有效。
      • 啊,但是您如何通过一个 lambda 表达式从 SFINAE 中受益?我的意思是,不能有任何后备,可以吗?
      • @piotrs。消费者可以询问给定的表达式是否是有效的调用,并有自己的回退。例如,如果有人修复了 std::function 的 ctor(bad std 坏库)以仅接受您可以通过签名实际调用的内容,则可以在两者之间分派一对重载 std::function&lt;void()&gt;std::function&lt;bool()&gt;
      猜你喜欢
      • 1970-01-01
      • 2017-08-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多