To take apart a pair, the following can be done
boost::bind(&std::pair::second, _1); // returns the value of a pair
What about using combinations of different containers, how can a nested pair be accessed?
For example when I wanted to partition a vector into items contained in a supplemental map and items that where not contained in the supplemental map I used the following:
typedef int DWORD; typedef std::pair<std::string, bool> user_info;
typedef std::map<DWORD, user_info> USER_MAP;
typedef std::vector<DWORD> VEC_STAFF;
VEC_STAFF::iterator it = std::partition(
Staff.begin(), Staff.end(),
(bind(&USER_MAP::find, m_Users, _1) != m_Users.end()));
Now I have a second problem - during the running of the application the status bool of user_info can change, and later on I want to re-partition the vector with items that have a status bool of true rather than just being contained in the supplemental map.
However I seem to have a problem accessing the second item of a nested pair.
I tried the following but I cannot seem to access the nested pair!
VEC_STAFF::const_iterator itCurEnd = partition(Staff.begin(), Staff.end(),
bind(&USER_MAP::value_type::second::second,
bind(&USER_MAP::find, &m_Users, _1)) == true);
Not sure I follow what's going on there, but usually when I start running into problems with bind I give up and implement a functor. This might simplify things in your case.
To me, the following is a lot easier to read than all that messing around with multiple levels of binds
template <class Arg>
struct Whatever : public std::unary_function<Arg, bool>
{
bool operator()(const Arg &arg1) const {
//logic here
}
};
Whatever<???> functor;
std::partition(Staff.begin(), Staff.end(), functor);
The syntax you used obviously doesn't work. The first "::second" already signifies a non-static member and not a type. If you have a pair inside a pair you probably have to use two bind calls:
typedef std::pair< int, bool > foo_t;
typedef std::pair< int, foo_t > bar_t;
.....
bind( &foo_t::second, bind(&bar_t::second,
bind( &USER_MAP::find, _1 )
) )
(I didn't test this. Perhaps this is what you want)
But three levels if bind is quite challenging, in my opinion.
Edit: How about this?
template<typename Iter, typename Return>
struct deref_2nd_2nd : std::unary_function<Iter, Return> {
Return operator()(Iter const& it) const {
return (*it).second.second;
}
};
.....
bind(
deref_2nd_2nd<USER_MAP::iterator,bool>(),
bind( &USER_MAP::find, _1 )
)
Related
I have a map of structs that holds several named values like this:
struct MyData {
MyType dataA;
std::string dataB;
int dataC;
};
typedef std::pair<std::string, MyData> PairType;
std::map<PairType::first_type, PairType::second_type> dataMap;
This is defined in a header file of a compilation unit that calls a function from a library.
Because the library function does not know about my type definitions, I can't pass dataMap directly.
The function only actually needs the dataA struct member and already knows about MyType, so I could pass a std::map<std::string, MyType> instead.
Whats the most elegant way of cutting just the data I need from the map of structs and save it into a new map with the same keys but only the type and values from dataA?
Preferably for C++0x without usage of boost or other external libraries, but solutions for newer standards are also welcome for educational purposes.
I'm basically looking for an equivalent of Python's
newDict = {key:value.dataA for (key,value) in oldDict.items()}
You can use a ranged based for loop to really easily make a copy. That would look like
std::map<std::string, MyType> my_type_map;
for (const auto& pair : dataMap)
{
my_type_map.emplace(pair.first, pair.second.dataA);
}
If you want this as a single expression, you are going to need something like boost::transform_iterator, either by including that, or writing an iterator yourself.
Given a conversion function (or equivalent lambda)
std::pair<std::string, MyType> convert(PairType& pair){
return { pair.first, pair.second.dataA };
};
You can declare newDict and populate it
/* can be const */ std::map<std::string, MyType> newDict {
boost::make_transform_iterator(oldDict.begin(), convert),
boost::make_transform_iterator(oldDict.end(), convert)
};
Or you can use a view type
auto newDict = boost::copy_range<std::map<std::string, MyType>>(oldDict | std::ranges::views::transform(convert));
I have two std::maps. One uses std::greater in the constructor so it is sorted the opposite direction:
std::map<key, value> map1;
std::map<key, value, std::greater> map2;
Currently I have two functions, one per map, each iterating over the elements and processing. However, given the processing logic is the same (only the map iteration direction is different) I wanted to replace these two functions with one:
template<bool useMap1>
void combinedFunc()
{
std::map<key, value>& map = useMap1 ? map1 : map2;
std::map<key, value>::iterator iter = map.begin();
// A fair amount of code iterating over the elements, hence wishing to combine
}
However, the compiler is rightfully saying that map1 and map2 are incompatible types.
Is there a way to reuse the code, even with std::greater?
Is there a way to reuse the code, even with std::greater?
Here's one way.
Create two overloaded functions for dealing with the two maps.
Move the core logic of dealing with the items of the maps to another function that works with iterators.
template <typename Iterator>
void coreFunction(Iterator start, Iterator end) { ... }
// For map1
void functionForMap(std::true_type dummyArgument)
{
coreFunction(map1.begin(), map1.end());
}
// for map2
void functionForMap(std::false_type dummyArgument)
{
coreFunction(map2.begin(), map2.end());
}
template<bool useMap1>
void combinedFunc()
{
functionForMap(std::integral_constant<bool, useMap1>());
}
Still simpler -- this requires only the first function.
template<bool useMap1>
void combinedFunc()
{
useMap1 ? coreFunction(map1.begin(), map1.end()) : coreFunction(map2.begin(), map2.end());
}
Instead of a template argument that implies what type to use, why not be direct and specify which type to use? Something like:
template<class M>
void combinedFunc(const M & map) // Drop "const" if necessary
{
M::iterator iter = map.begin();
// A fair amount of code iterating over the elements, hence wishing to combine
}
The caller is then responsible for specifying the map.
combinedFunc(map1); // The template parameter should be deducible.
This has the benefit of not locking your template to only two specific maps. On the downside, the caller has to know about map1 and map2. This might be undesirable if combinedFunc is part of a public interface, while the maps are not. In that case, you could write a wrapper function for the interface. Something simple like the following should work.
void publicFunc(bool useMap1)
{
if ( useMap1 )
combinedFunc(map1);
else
combinedFunc(map2);
}
Note that this calls two distinct functions even though the syntax makes it look like the same one. (You cannot do something like combinedFunc(useMap1 ? map1 : map2);.)
I have a map that uses pairs of some datatype KT as keys to map to a matrix type, i.e. sth. like
std::map<std::pair<KT,KT>, MatType, PairCompare>
For comparison I only need the first element of the pair, so PairCompare is very simple
struct PairCompare
{
bool operator()(const std::pair<KT,KT>& lhs,const std::pair<KT,KT>& rhs) const
{return lhs.first<rhs.first;}
};
I would however like to use the whole pair as a key, as I constantly need the second element in operations while iterating through the map.
Sometimes, I also need to find a map entry based on a single KT only. Of course I should use a pair of KT in the find() routine, but I would like to avoid creating a dummy pair of KT, as I have to do this many times and that could get expensive. I would like to use something like
std::map<std::pair<KT,KT>, MatType, PairCompare> mymap;
KT mykey = // ... some implementation of KT;
// fill map
auto it = mymap.find(mykey); // <- will not work of course, but what I would like to use
auto it = mymap.find(std::pair<KT,KT>(mykey,mykey)); // <- what I am using so far (creating a dummy pair)
Mykey can in general be both lvalue and rvalue (in my application).
Is there any way of defining a different type of key that contains two KT instances and only uses one for map ordering and also enables finding by single KTs that works straight forward? Can it be done with some special comparison object? Maybe there is also a smart way of getting around using pairs of KT as Key at all, but still enabling access to the second KT in map iterations?
Thanks for your help!
P.S.: to be precise, as KT I am using
typedef std::vector<int> KT
Your problem is that you think of keys as "pair of X,Y". Think of the key as "an object that supports this and that operations":
template<typename K1, typename K2>
class Key
{
K1 v1_;
boost::optional<K2> v2_;
public:
Key(K1 v1): v1_{ std::move(v1) }, v2_{} {}
Key(K1 v1, K2 v2): v1_{ std::move(v1) }, v2_{ std::move(v2) } {}
bool operator==(const Key<K1,K2>& other)
{
if(!v2_ || !other.v2_)
return v1_ == other.v1_;
return std::tie(v1_, *v2_) == std::tie(other.v1_, *other.v2_);
}
// implement other comparisons, as required
};
using KeyType = Key<int,std::string>;
std::map<KeyType, MatType> YourMap;
// add key comparable by first element:
YourMap[KeyType{0}] = MatType{}; // match KeyType{0, "any string"}
// add key comparable by both elements:
YourMap[KeyType{1, "test"}] = MatType{}; // match KeyType{1, "test"}
Attempting to force the key to be a pair here complicates the problem.
The Boost documentation doesn't elaborate much, but there is an (optional) KeyCompare function that can be passed to the ptree.
Anyone have a good example of using a custom KeyCompare function?
I have recently been working with a ptree that is real slow. My keys are long strings (paths), and I assuming it's the string comparisons that make it slow.
From what I can glean, the default KeyCompare is std::less(), I want to change this. I think something that just compares the hashes of the two strings.
It goes without saying (but I'll say it anyway) that I would use a different object for the key to facilitate this: Something that has (std::string+hash), rather than just a std::string. The hash would be calculated during construction.
Thanks,
Rik.
Found this from the boost source code: An example of a case-insensitive KeyCompare:
template<class T>
struct less_nocase
{
typedef typename T::value_type Ch;
std::locale m_locale;
inline bool operator()(Ch c1, Ch c2) const
{
return std::toupper(c1, m_locale) < std::toupper(c2, m_locale);
}
inline bool operator()(const T &t1, const T &t2) const
{
return std::lexicographical_compare(t1.begin(), t1.end(),
t2.begin(), t2.end(), *this);
}
};
Then all you need to do is pass it in to the basic_ptree class:
typedef basic_ptree<std::string, std::string,
less_nocase<std::string> > iptree;
I want to achieve something like this with boost multi_index_container and composite_key:
struct LogicalAnd {
bool operator()(const int& argVal1, const int& argVal2) const {
return int(argVal1 & argVal2) == argVal1;
}
};
template<class T, class Enable = void>
class FooContainer;
template <class T>
struct FooContainer<T,typename boost::enable_if<boost::is_base_of<IFoo, T> >::type> {
typedef multi_index_container<
boost::shared_ptr<T>,
indexed_by<
hashed_non_unique<
composite_key<
T,
const_mem_fun<T,int,&T::getKey1>,
const_mem_fun<T,int,&T::getKey2>
>,
composite_key_equal_to<
LogicalAnd,
LogicalAnd
>
>
>
> shared_ptr_type;
};
Knowing that:
namespace CustomKey {
typedef enum {
VAL1 = 0x00000001,
VAL2 = 0x00000002,
ALL = 0xFFFFFFFF
} type;
}
The goal is to be able to perform the following:
container.find(boost::make_tuple(CustomKey::VAL1, CustomKey::ALL));
Which would allow me to retrieve all elements for which LogicalAnd returns true.
The problem is that I can't manage to get my LogicalAnd comparator to work with my multi_index_container.
I can get it to build by adding a composite_key_hash right before composite_key_equal_to:
composite_key_hash<
boost::hash<int>,
boost::hash<int>
>
But find operation does not work as expected so it does not change much...
I've searched boost documentation, and I've tryed various implementations, but I'm getting drown in the amount of information...
Any help is appreciated!
You're using a hash for your multi-index.
That means the LogicalAnd comparator never gets called unless something is found in the right hash bucket.
0x01 and 0xFF don't hash to the same value even though 0x01 & 0xFF == 0x01. That is, LogicalAnd would return true, but it's never invoked.
You would need a hash function which is invariant wrt. LogicalAnd, and I don't think that's possible. By design most hash functions are supposed to minimise collisions between different key values.
You need to come up with some different indexing system, I'm afraid.