[英]C++ map with custom value_type
For a std::map<K, V>
the default value_type
is std::pair<const K, V>
. 对于
std::map<K, V>
的默认value_type
是std::pair<const K, V>
。 Is there a way to use a custom value_type
? 有没有一种使用自定义
value_type
? As far as I can tell you can't. 据我所知你做不到。
Edit: To be clear, a custom value_type
might be something like this: 编辑:要清楚,自定义
value_type
可能是这样的:
struct Edge {
K from;
V to;
int calculate_thing();
void print_debug();
};
Eg suppose I have some existing function that I don't want to change like this: 例如,假设我有一些不想更改的现有功能:
template<typename It>
void processEdges(It begin, It end) {
for(auto it = begin; it != end; ++it) {
do_stuff(it->from);
do_more_stuff(it->calculate_thing());
}
}
It's always std::pair<const K, V>
, you can't change that. 它始终是
std::pair<const K, V>
,您不能更改它。
If you need a custom value_type
, maybe you could use std::set
(preferably with a transparent comaprator ). 如果您需要自定义
value_type
,则可以使用std::set
(最好使用透明的comaprator )。
You could add a level of indirection via an adapter class. 您可以通过适配器类添加间接级别。 Something like below (examples adapting map, or individual map iterators, and showing don't have to change target function for vectors)...
如下所示(修改地图或单个地图迭代器的示例,并显示不必更改矢量的目标函数)...
// main.cpp
#include <iostream>
#include <map>
#include <vector>
#include <type_traits>
// https://stackoverflow.com/questions/56887842/c-map-with-custom-value-type
// From the original question
template <typename K, typename V>
struct Edge {
K from;
V to;
int calculate_thing() { return 0; }
void print_debug() { std::cout << "from='" << from << "', to='" << to << "'\n"; }
};
void do_stuff(int) {}
void do_more_stuff(int) {}
template<typename It>
void processEdges(It begin, It end) {
for(auto it = begin; it != end; ++it) {
do_stuff(it->from);
do_more_stuff(it->calculate_thing());
it->print_debug();
}
}
// An additional level of indirection for maps
template <typename TMapIterator>
class MapValueIterator {
private:
TMapIterator map_iterator;
typedef typename std::iterator_traits<TMapIterator>::value_type map_iterator_type;
public:
typedef ptrdiff_t difference_type;
typedef typename map_iterator_type::second_type value_type;
typedef value_type & reference;
typedef value_type * pointer;
typedef std::forward_iterator_tag iterator_category;
MapValueIterator(TMapIterator map_iterator) : map_iterator(map_iterator) {}
MapValueIterator(MapValueIterator &other) { map_iterator = other.map_iterator; }
~MapValueIterator() {}
MapValueIterator& operator=(MapValueIterator &other) { map_iterator = other.map_iterator; return *this; }
MapValueIterator operator++() { map_iterator++; return *this; }
value_type* operator*() const { return &map_iterator->second; }
MapValueIterator operator++(int) {
TMapIterator next_map_iterator(map_iterator);
next_map_iterator++;
return MapValueIterator(next_map_iterator);
}
value_type* operator->() const { return &map_iterator->second; }
friend bool operator== (MapValueIterator const &left, MapValueIterator const &right) { return left.map_iterator == right.map_iterator; }
friend bool operator!= (MapValueIterator const &left, MapValueIterator const &right) { return left.map_iterator != right.map_iterator; }
};
template <typename TMap>
class MapValueAdapter {
TMap ↦
public:
MapValueAdapter(TMap &map) : map(map) {}
MapValueIterator<typename TMap::iterator> begin() { return MapValueIterator<typename TMap::iterator>(this->map.begin()); }
MapValueIterator<typename TMap::iterator> end() { return MapValueIterator<typename TMap::iterator>(this->map.end()); }
};
// Map detection cribbed from https://stackoverflow.com/questions/45042233/detect-if-type-is-a-mapping
template <typename T>
struct is_pair : std::false_type { };
template <typename T, typename U>
struct is_pair<std::pair<T, U>> : std::true_type { };
template <typename T>
constexpr bool is_pair_v = is_pair<T>::value;
template <typename TContainer>
typename std::enable_if<
is_pair_v<typename std::iterator_traits<typename TContainer::iterator>::value_type>,
MapValueAdapter<TContainer>
>::type
adapt(TContainer &container) { return MapValueAdapter (container); }
template <typename TIterator>
typename std::enable_if<
is_pair_v<typename std::iterator_traits<TIterator>::value_type>,
MapValueIterator<TIterator>
>::type
adapt(TIterator iterator) { return MapValueIterator (iterator); }
template <typename TContainer>
typename std::enable_if<
!is_pair_v<typename std::iterator_traits<typename TContainer::iterator>::value_type>,
TContainer &
>::type
adapt(TContainer &container) { return container; }
int main(void)
{
// Example where std::map, std::map::iterator and std::vector are adapted for processEdges() call.
std::map<int, Edge<int, char>> map;
map.insert_or_assign(2, Edge<int, char>{2, '2'});
map.insert_or_assign(1, Edge<int, char>{1, '1'});
std::vector<Edge<int, char>> const vector = { { 3, '3'}, {4, '4'} };
auto map_adapter = adapt(map);
auto vector_adapter = adapt(vector);
std::cout << "Starting" << std::endl;
std::cout << "Map\n";
processEdges(map_adapter.begin(), map_adapter.end());
std::cout << "Map Iterator\n";
processEdges(adapt(map.begin()), adapt(map.end()));
std::cout << "Vector\n";
processEdges(vector_adapter.begin(), vector_adapter.end());
std::cout << "Finished" << std::endl;
}
The output is: 输出为:
Starting Map from='1', to='1' from='2', to='2' Map Iterator from='1', to='1' from='2', to='2' Vector from='3', to='3' from='4', to='4' Finished
you can use boost variant for this 您可以为此使用boost变体
typedef boost::variant<std::string, std::map<std::string, std::string>> Value;
typedef std::map<std::string, Value> TheMapYouWouldUse;
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.