Let's take (as a demo example) a simple counting algorithm for getting the max count of characters in a string.
A typical C++17 implementation could be:
#include <iostream>
#include <unordered_map>
#include <string_view>
#include <algorithm>
#include <utility>
using Counter = std::unordered_map<char, std::size_t>;
using Pair = Counter::value_type;
constexpr std::string_view s{ "abbcccddddeeeeeffffff" };
int main() {
Counter counter{};
for (const char c : s) counter[c]++;
const auto& [letter, count] = *std::max_element(counter.begin(), counter.end(),
[](Pair& p1, Pair& p2) { return p1.second < p2.second; });
std::cout << "\n\nHighest count is '" << count << "' for letter '" << letter << "'\n\n";
}
In C++20 we have projections and can use pointer to structure member elements for the projection (and give that to the underlying std::invoke
).
The solution would be a little bit shorter, not sure, if better (for whatever criteria). Anyway:
#include <iostream>
#include <unordered_map>
#include <string_view>
#include <algorithm>
using Counter = std::unordered_map<char, std::size_t>;
namespace rng = std::ranges;
constexpr std::string_view s{ "abbcccddddeeeeeffffff" };
int main() {
Counter counter{};
for (const char c : s) counter[c]++;
const auto& [letter, count] = *rng::max_element(counter, {}, &Counter::value_type::second);
std::cout << "\n\nHighest count is '" << count << "' for letter '" << letter << "'\n\n";
}
But, Im not sure about taking the address of a containers data member, residing in the std::namespace
. Is this OK?
The only restrictions I see in [namespace.std] are about pointers to member functions. I can't find anything that would disallow taking a pointer to a (public) data member of a standard library class.
This also makes sense, since the restrictions for functions are there to allow the standard library implementation to choose a different overload set than described in the standard, as long as direct calls still work as specified. However, there is no similar choice the implementation could make for a data member that is specified in the public interface (not for exposition only).
So I don't see anything wrong with &Counter::value_type::second
.