绑定模板化的标准库函数

Binding a templated standard library function

本文关键字:标准 库函数 绑定      更新时间:2023-10-16

如何做到这一点?替代方案需要将std::generate封装在lambda或std::function中,这是不可取的。

int main()
{
    using array_int = std::array<int, 10>;
    std::vector<array_int> vec(10);
    std::for_each(vec.begin(), vec.end(),
        std::bind(std::generate, std::placeholders::_1, []() { return 0; }));
    return 0;
}

如前所述,问题是std::generate采用迭代器对。让我们假设它们是助推范围:

boost::for_each(vec,
    boost::bind(boost::generate, _1, []() { return 0; }));

我假设您真的要向generate传递一些更有用的东西,因为这些数组已经被零填充,因为vector值会初始化它们。

绑定表达式不会向generate传递正确数量的参数,因此指定所需的generate的专用化并不是唯一的问题。为了说明专业化,你需要知道你想要传递的生成器的类型,它是一个lambda,所以你需要把它取出来:

auto gen = [] { return 0; };

然后你需要说你想要哪个generate

std::generate<array_int::iterator, decltype(gen)>

然后你需要把正确的论点传递给它:

std::bind(std::generate<array_int::iterator, decltype(gen)>,
          std::bind(&array_int::begin, std::placeholders::_1),
          std::bind(&array_int::end, std::placeholders::_1),
          gen));

这仍然不起作用,因为array_int::beginarray_int::end重载了,所以需要将它们强制转换为array_int::iterator (array_int::*)()才能获得非常量版本。

auto gen = [] { return 0; };
using memfunc = array_int::iterator (array_int::*)();;
std::bind(std::generate<array_int::iterator, decltype(gen)>,
          std::bind((memfunc)&array_int::begin, std::placeholders::_1),
          std::bind((memfunc)&array_int::end, std::placeholders::_1),
          gen));

您可以使用generate_n使其简单一点,因为您知道大小,并且可能使用data()而不是begin(),尽管您仍然需要投射它:

auto gen = [] { return 0; };
using memfunc = int* (array_int::*)();;
std::bind(std::generate_n<int*, int, decltype(gen)>,
          std::bind((memfunc)&array_int::data, std::placeholders::_1),
          10,
          gen));

或者你可以使用lambda:

std::for_each(vec.begin(), vec.end(), [](array_int& a) {
  std::generate(a.begin(), a.end(), []{ return 0; });
});

如果您想调用boost::generate,这会更容易一些,因为您不需要嵌套的绑定表达式,但您仍然需要生成器的类型:

auto gen = [] { return 0; };
std::bind(boost::generate<array_int, decltype(gen)>,
          std::placeholders::_1
          gen);

或者使用lambda:

std::for_each(vec.begin(), vec.end(), [](array_int& a) {
  boost::generate(a, []{ return 0; });
});