【问题标题】:How to modify the result of a bound member function for std::generate如何修改 std::generate 的绑定成员函数的结果
【发布时间】:2017-11-11 00:01:35
【问题描述】:

我正在使用 VS2008 兼容代码和 Boost 1.60(没有 C++ 11)。我有一个第三方库,它返回一个类似列表的界面。我想获取列表的元素并将它们放在 std::vector 中。 track_list 类有一个 next 方法,它返回指向轨道指针 track** 的指针。

我在想我可以使用 std::generate 来填充与track_list 相同大小的向量。我能够想出boost::bind(&track_list::next, tracks),它让我得到track**,但我不确定如何添加取消引用部分以让track*进入vector<track*>

此外,我知道实际上有一个specific_track* 可以安全地从track* 转换为。所以我真正想要的是类似于(specific_track*)(*boost::bind(&track_list::next, tracks)) 的东西,但我不确定如何在语法上构建它。我在正确的轨道上吗?我查看了 boost lambda,但生成器函数没有参数。

编辑:也许一个更简单的例子可能有助于澄清我正在尝试做的事情。

int** get_ptr_num() { int* i = new int(5); return new int*(i); }
int* get_num() { return new int(5); }

int main() {
  std::vector<int*> nums(10);
  std::generate(nums.begin(), nums.end(), get_num) // compiles      
  std::generate(nums.begin(), nums.end(), get_ptr_num) // cannot convert from int** to int*
}

基本上,我只想将 get_ptr_num 包装在某种绑定或 lambda 中以执行取消引用,而无需创建单独的函数来执行此操作。

第二部分,演员,大概是这样的:

int main() {
  std::vector<double*> nums(10);    
  std::generate(nums.begin(), nums.end(), get_ptr_num) // cannot convert from int** to double*
}

这似乎用 C++ 11 lambdas 做起来很简单,但我不能使用 C++ 11。

关于 this 作为成员函数的最后一部分可能更像这样:

class IntGenerator {
public:
  int** get_ptr_num() { int* i = new int(5); return new int*(i); }
}

int main() {
  IntGenerator int_gen;
  std::vector<int*> nums(10);
  std::generate(nums.begin(), nums.end(), boost::bind(&IntGenerator::get_ptr_num, int_gen)) // cannot convert from int** to int*

}

【问题讨论】:

  • 您的目标是创建向量,还是探索积极使用标准库的技术?将列表的内容复制到向量中很容易:只需使用每个元素调用 push_back
  • 我真的不清楚你想做什么。你有什么代码?它做了什么你不想要的。如果您正在寻找代码审查,那么这些与堆栈溢出无关。此外,在同一个问题中问一堆半相关的问题也不是很好的形式。最重要的是,我什至不清楚这个问题与标题有何关系。
  • 对不起,我以为问题很清楚。如何使用 Boost bind/lambdas 为 std::generate 编写生成器函数以获取 track** 并将其转换为 specific_track*
  • 这不是代码审查,第二部分是在第一部分的基础上构建的。我不确定您为什么看不到这个问题与标题的关系。函数nexttrack_list 的绑定成员函数,但返回值不是我需要的;我需要取消引用并转换它,我正在寻找某种 lambda 来做到这一点。

标签: c++ boost stl


【解决方案1】:

您可以使用函数输入迭代器:

Live On Coliru

#include <boost/iterator/function_input_iterator.hpp>
#include <vector>
#include <functional>
#include <iostream>
#include <array>

namespace TheAPI {

    struct track_list {
        std::array<char const*, 6> titles {{ "one", "two", "three", "four", "five", "six" }};
        size_t length() const { return titles.size(); }

        struct Iterator {
            char const* const* raw;
            char const* next() { return *raw++; }
        };

        Iterator get_iterator() const { return {titles.begin()}; };
    };

}

int main() {
    TheAPI::track_list tl;
    auto iter = tl.get_iterator();

    auto gen = std::bind(&TheAPI::track_list::Iterator::next, std::ref(iter));

    auto first = boost::make_function_input_iterator(gen, 0),
         last  = boost::make_function_input_iterator(gen, 6);

    std::vector<std::string> titles(first, last);

    std::copy(titles.begin(), titles.end(), std::ostream_iterator<std::string>(std::cout, "\n"));
}

当然,如果您考虑使用generate,则使用generate_n 会更简单:

Live On Coliru

#include <functional>
#include <iterator>
#include <algorithm>
#include <iostream>
#include <array>

namespace TheAPI {

    struct track_list {
        std::array<char const*, 6> titles {{ "one", "two", "three", "four", "five", "six" }};
        size_t length() const { return titles.size(); }

        struct Iterator {
            char const* const* raw;
            char const* next() { return *raw++; }
        };

        Iterator get_iterator() const { return {titles.begin()}; };
    };

}

int main() {
    TheAPI::track_list tl;
    auto iter = tl.get_iterator();

    auto gen = std::bind(&TheAPI::track_list::Iterator::next, std::ref(iter));
    std::generate_n(std::ostream_iterator<std::string>{std::cout, "\n"}, tl.length(), gen);
}

使用填充向量

std::vector<std::string> my_vector;
std::generate_n(back_inserter(my_vector), tl.length(), gen);

两个程序都打印

one
two
three
four
five
six

【讨论】:

猜你喜欢
  • 1970-01-01
  • 2012-08-22
  • 2020-11-07
  • 1970-01-01
  • 2021-04-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多