-
Notifications
You must be signed in to change notification settings - Fork 69
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Eliminating the difference in what an iterator yields #32
Comments
Hello, Compared to a The possible design choices I thought of:
I picked-up the current solution as a compromise to avoid the undefined behaviour or error-prone solutions aforementioned. There may be a better solution that I may have missed and any suggestion is welcome. |
@Tessil Instead of returning a std::pair, the iterators could instead return a custom pair type, eg a tsl::ordered_map::pair value. This new type would replicate the structure of a std::pair, but add some additional structure that would allow for mutating the 'second' field. |
A custom pair would solve the range-based for-loop problem though it would not really be possible to expose a A lot of issues are open on this |
Interesting. I switched to tsl::sparse_map from absl::flat_hash_map, which was transparent except that I had to add:
in one spot, due to this issue. So absl::flat_hash_map doesn't present this difficulty despite being a flat hash table. Have you happened to look at how they did it? |
Hi, From my understanding
(source) If the two pairs are not layout compatible it is forced to copy Example: #include <functional>
#include <iostream>
#include "absl/container/flat_hash_map.h"
class A {
public:
A(int i) : m_i(i) { std::cout << "constructor" << std::endl; }
A(const A& other) {
std::cout << "copy constructor" << std::endl;
m_i = other.m_i;
}
A(A&& other) noexcept {
std::cout << "move constructor" << std::endl;
m_i = other.m_i;
}
A& operator=(const A& other) {
std::cout << "copy assignement" << std::endl;
m_i = other.m_i;
return *this;
}
A& operator=(A&& other) noexcept {
std::cout << "move assignement" << std::endl;
m_i = other.m_i;
return *this;
}
virtual void foo() {}
bool operator==(const A& other) const { return m_i == other.m_i; }
public:
int m_i;
};
namespace std {
template <>
struct hash<A> {
size_t operator()(const A& a) const { return hash<int>()(a.m_i); }
};
} // namespace std
int main() {
std::cout << absl::container_internal::memory_internal::IsLayoutCompatible<
A, int>::value
<< std::endl;
absl::flat_hash_map<A, int> map = {{A(1), 1}, {A(2), 2}};
std::cout << "reserve" << std::endl;
map.reserve(32);
} Output:
If you remove the virtual method the layouts will be compatible and you then have:
If you replace The crux of the problem is that I would like to store a |
From your documentation you have this:
Is this something that could be eliminated? I.e. the divergence between ordered_map and unordered_map? I have code that iterates over an unordered_map in parallel using std::for_each. I need to modify the T values but with ordered_map I can't do this because the callback provided to for_each receives the dereferenced iterator, i.e. I end up with a const std::pair<Key, T> and thus have no way of calling value to get a modifiable T.
It also pops up in using the ranged-for loops:
for(auto& foo : some_ordered_map)
foo here is again const std::pair<Key, T> and thus I can't possibly call value even if I wanted to, meaning I have to change all ranged-for loops to be the older, non-ranged style.
The text was updated successfully, but these errors were encountered: