3

说我有

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 | boost::adaptors::map_values 并允许在 MyClass 方法之外方便地进行值迭代。如何声明这样的方法?我需要实现某种伪容器和相应的迭代器还是有捷径?

4

2 回答 2

1

基本上,您有两个不错的选择。您可以使用 boost's 为用户提供一个很好的解耦界面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; }
}; 
于 2014-01-29T22:22:33.633 回答
1

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

因此,如果您希望直接使用调整后的范围,您可以简单地使用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; }
}
于 2014-01-31T11:02:03.137 回答