通过在每个元素上调用name(),将Class的向量转换为decltype(Class :: name())的向量

Pat*_*ryk 3 c++ boost vector c++11

拥有以下结构MyStruct:

struct MyStruct {                                                                                                                                                                                      
  explicit MyStruct(std::string name) : name_(name){}
  std::string name() const { return name_; }
private:
  std::string name_;
};
Run Code Online (Sandbox Code Playgroud)

我想变换std::vectorMyStructs到一个std::vector<std::string>.我设法做到这样:

#include <iostream>
#include <string>
#include <vector>

#include <boost/range/adaptor/transformed.hpp>

struct MyStruct {
  explicit MyStruct(std::string name) : name_(name){}
  std::string name() const { return name_; }
private:
  std::string name_;
};

int main() {
  std::vector<MyStruct> vm;
  vm.emplace_back("asd");
  vm.emplace_back("qwe");
  vm.emplace_back("zxc");

  using namespace boost::adaptors;
  auto vs = vm | transformed([](const MyStruct& c){return c.name();});

  for (const auto& c : vs) std::cout << c << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

但后来vs不是矢量而是:

const boost::range_detail::transformed_range<(lambda at /tmp/main.cpp:21:36), std::vector<MyStruct, std::allocator<MyStruct> > > => const boost::range_detail::transformed_range<(lambda at /tmp/main.cpp:21:36), std::vector<MyStruct, std::allocator<MyStruct> > >
Run Code Online (Sandbox Code Playgroud)

我怎样才能做到这一点?我希望在初始化向量时这样做 - 不是通过声明向量然后std::copy或类似的东西.

我知道我可以做类似的事情:

std::vector<std::string> vv; 
vv.reserve(boost::size(vs));
boost::copy(vs, std::back_inserter(vv));
Run Code Online (Sandbox Code Playgroud)

但我想要一步初始化(最好用const限定符).

我相信这是我需要的某种高阶(功能)映射函数或std/boost /手写等效函数.

Bar*_*rry 5

我建议使用range-v3,这基本上是新的和改进的Boost.Ranges.在那里,它只是:

std::vector<std::string> vs = vm | ranges::view::transform(&MyStruct::name);
Run Code Online (Sandbox Code Playgroud)

请注意,如果你捕获了这个auto,你就不会得到一个vector.生成的对象具有转换运算符.

使用Boost.Ranges,你不能本机地这样做,但你可以编写自己的管道适配器:

struct make_vector_t
{
    template <class R>
    friend auto operator|(R&& range, make_vector_t)
    {
        using std::begin;
        using std::end;

        using value_type = typename iterator_traits<decltype(begin(range))>::value_type;
        return std::vector<value_type>(begin(range), end(range));
    }
} constexpr make_vector{};
Run Code Online (Sandbox Code Playgroud)

并使用它:

auto vs = vm 
    | transformed([](const MyStruct& c){return c.name();});
    | make_vector;
Run Code Online (Sandbox Code Playgroud)