`map::operator[]` may create a new `string` -> `int` mapping. But it
doesn't know how to create a `string` key from a `string_view`
key-comparable. Or from say a `double` key comparable, if one defined
such comparison (simply casting to `string` wouldn't even compile).
You may use code like the following, which I believe both clarifies the
issues and is one practical solution.
I chose to also address the silly `no operator[] for const` issue, but
this just-cobbled-together code lacks support for custom comparators.
#include <functional>
#include <map>
#include <stdexcept>
#include <string>
#include <string_view>
#include <utility>
using namespace std::literals;
namespace my {
using std::less,
std::map,
std::out_of_range,
std::string,
std::string_view,
std::forward;
template< class Key >
struct Default_key_factory_
{
template< class Key_id >
static auto make_key( Key_id&& key_id )
-> Key
{ return Key( forward<Key_id>( key_id ) ); }
};
template< class Key_, class Item_, class Key_factory_ =
Default_key_factory_<Key_> >
class Map_:
private map<Key_, Item_, less<>>
{
public:
using Key = Key_;
using Key_factory = Key_factory_;
using Item = Item_;
using Self = Map_;
using Std_map = map<Key, Item, less<>>;
using Std_map::Std_map;
using Std_map::find;
using Std_map::count;
using Std_map::lower_bound;
using Std_map::upper_bound;
using Std_map::equal_range;
template< class Key_id >
auto forced_item( const Key_id& key_id )
-> Item&
{
const auto it = Self::find( key_id );
if( it == Self::end() ) {
return Std_map::operator[]( Key_factory::make_key(
key_id ) );
}
return it->second;
}
template< class Key_id >
auto operator[]( const Key_id& key_id ) -> Item& { return
forced_item( key_id ); }
template< class Key_id >
auto operator[]( const Key_id& key_id ) const
-> const Item&
{
const auto it = Self::find( key_id );
if( it == Self::end() ) {
throw out_of_range( "const-Map_::operator[] - no such
key." );
}
return it->second;
}
};
} // namespace my
auto main() -> int
{
std::string_view key = "foo"sv;
my::Map_<std::string, int> a;
auto it_a = a.find(key); // OK
std::map<std::string, int, std::less<>> b;
auto it_b = b.find(key); // OK
//b[key] = 3; //! Gah
// binary '[': no operator found which takes a right-hand operand
of type 'std::string_view'
a[key] = 3; // OK
b[std::string(key)] = 3; // OK but may construct a std::string
without reason.
}
- Alf