【问题标题】:std::bind and function templatesstd::bind 和函数模板
【发布时间】:2016-04-26 08:32:29
【问题描述】:

我目前正在尝试使用std::bind 从函数模板创建std::function<void()>

template<class Iterator>
void printRange(Iterator first, Iterator last) {
    std::copy(first, last, std::ostream_iterator<typename Iterator::value_type>(std::cout, " "));
    std::cout << std::endl;
}

从概念上讲,我想要的是

int main() {
    std::vector<int> v{1, 2, 3};
    auto f0 = std::bind(printRange, v.begin(), v.end()); // won't compile, of course
    f0();
    return 0;
}

我知道这不会编译,我必须先实例化函数模板才能实际使用它。例如,以下替代方案会起作用:

auto f1 = std::bind(printRange<std::vector<int>::const_iterator>, v.begin(), v.end());
auto f2 = std::bind(printRange<decltype(v.begin())>, v.begin(), v.end());
auto f3 = [&v]() { printRange(v.begin(), v.end()); };

我已经创建了一个便利函数

template<class Iterator>
std::function<void()> makePrintRangeFunction(Iterator first, Iterator last) {
    return std::bind(printRange<Iterator>, first, last);
}

简化流程:

auto f4 = makePrintRangeFunction(v.begin(), v.end());

我想知道是否可以创建一个更通用的std::function&lt;void()&gt; 生成器,接受函数模板作为第一个参数,函数模板参数作为可变长度参数列表?如果不使用内置语言功能,也许通过宏?

【问题讨论】:

  • 并且不能接受 lambda?
  • 是的,fwiw,我发现 lambdas 对于过去需要bind 的所有事情都更容易编码和阅读。
  • @TemplateRex:在这种情况下,lambda 是可以的,但是一旦我需要捕获多个变量,我认为std::bind 会产生一个更具可读性的表达式...
  • @Marcel,只需使用一个非常“薄”的 lambda,它会立即调用实际函数。这将与绑定一样可读。如果您想查看示例,请告诉我。

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


【解决方案1】:

只要你不需要模板函数返回类型,你可以这样做:

#include <functional>
#include <iostream>
#include <typeinfo>


template<typename ... T>
std::function<void()> makePrintRangeFunction(void (*f)(T...), T... param) {
    return std::bind(f, param...);
}

template<typename T, typename V>
void print(T type, V val)
{
    std::cout << typeid(type).name() << '\n' << val << '\n';
}

int main()
{
    int i = 5;
    double d = 10.5;
    auto f = makePrintRangeFunction(print, i, d);
    f();
}

【讨论】:

  • 这正是我想要的!非常感谢!
【解决方案2】:

也许下面的代码会有所帮助:)

template <class F, class... Args>
void test(F&& f, Args&&... args) {
 std::function<typename std::result_of<F(Args...)>::type()> task(
   std::bind(std::forward<F>(f), std::forward<Args>(args)...));
   task();
}

【讨论】:

  • 哦,我没听明白,我想第二个答案就是你想要的。
【解决方案3】:

如果您的编译器支持 C++14,您可以将通用 lambda 包装器定义为:

template<typename F>
auto fungen(F f) {
  return [=](auto... args) { f(args...); };
}

用例:

int main() {
  std::vector<int> v {1, 2, 3, 4};
  auto f = fungen(printRange<std::vector<int>::iterator>);
  f(v.begin(), v.end());
}

Live Demo

【讨论】:

  • 我真的不知道您的解决方案与 auto f1 = std::bind(printRange&lt;std::vector&lt;int&gt;::const_iterator&gt;, v.begin(), v.end()); 有什么不同,还是我遗漏了什么?
  • 看来 OP 希望编译器从函数参数中推断出模板参数。用例:auto f = fungen(printRange, v.begin(), v.end());。可悲的是,模板模板仅适用于类类型,我看不出是否可以在这种情况下扭曲模板参数推导。
  • @Revolver_Ocelot: ...如果我改用类类型,我将不得不再次明确模板参数,对吗?
猜你喜欢
  • 1970-01-01
  • 2019-04-30
  • 2014-01-09
  • 1970-01-01
  • 2019-01-18
  • 1970-01-01
  • 1970-01-01
  • 2013-01-21
  • 1970-01-01
相关资源
最近更新 更多