如何声明增强范围适配器(例如map_values)

时间:2014-01-28 14:26:27

标签: c++ boost c++11 map boost-range

说我有

class Value;
class Key;

class MyClass {
  private:
  std::map<Key,Value> my_map;
  ....
}

在MyClass方法中,我有一个非常方便的方法来通过说

来迭代my_map的值
 for( auto& value: my_map | boost::adaptors::map_values) {
    ...
 }

但是我希望有一个基本上输出的MyClass方法      my_map |提高::适配器:: map_values 并允许在MyClass方法之外进行方便的值迭代。我该如何申报这样的方法?我是否需要实现某种伪容器和相应的迭代器或者有一个快捷方式?

2 个答案:

答案 0 :(得分:1)

基本上,你有两个不错的选择。您可以使用boost any_range为用户提供一个很好的解耦接口,否则如果您需要最佳性能,您可以使用c ++ 11 decltypes让客户直接访问适应范围。在第一种情况下,如果更改实现,客户端将不必更改,但这需要额外的重定向。

使用any_range

#include <boost/range.hpp> 
#include <map> 
#include <boost/range/adaptor/map.hpp> 
#include <boost/range/any_range.hpp>

class Foo 
{ 
    std::map<int, int> my_map;
    boost::any_range<int, boost::forward_traversal_tag, int&, std::ptrdiff_t> Values()
    { return my_map | boost::adaptors::map_values; }
}; 

提供直接访问权限(这里的语法很难,因为你需要VS2013,它不支持类范围内未评估上下文中的成员变量):

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

class Foo 
{ 
    std::map<int, int> my_map;
    auto Values() -> decltype(my_map | boost::adaptors::map_values)
    { return my_map | boost::adaptors::map_values; }
}; 

答案 1 :(得分:1)

使用伪容器或迭代器适配器(例如boost :: iterator_range)并非绝对必要。虽然理论上使用适当的适配器(如iterator_range)会更加正确和通用,并且不会违反应用于对象的principle of least knowledge,但您可能希望避免它因为额外的间接,或者可能因为您的迭代器通常只有单程范围,而不是前进范围。

因此,如果您希望直接使用适应范围,只需使用decltype推导出适配器已经返回的迭代器类型:

#include <iostream>
#include <map>

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

class A {
  std::map<int,int> my_map = { {0, 1}, {2, 3} };
public:
  decltype(my_map | boost::adaptors::map_values)
  values() { return my_map | boost::adaptors::map_values; }
};

int main() {
    for (const auto& v : A().values())
        std::cout << "v = " << v << std::endl;
    return 0;
}
/* Output:
v = 1
v = 3
*/

如果你希望暴露的值是一个const成员函数,它会更复杂:

class A { 
...
  decltype(const_cast<const std::map<int,int>&>(my_map) | boost::adaptors::map_values)
  values() const { return my_map | boost::adaptors::map_values; }
}