Reputation: 309
I want to implement custom "at" method, which gives more informative exception if some key does not exists in some container (in particular vector/map/deque/unordered_map). However, in my project i have to do some casting of key types (i.e passing int variable as a key to std::map<uint16_t, some_type>) and there is too much cases like this, so i can't modify client code in order to avoid it. And project settings set to trait all warnings as errors, so this cast fails my build because of possible loss of data. To avoid it, i need to cast passed key.
I wrote this:
template <typename CntT, typename KeyT>
auto at(const CntT& container, const KeyT& key) -> decltype(container.at(key))
{
using CKeyType = ContainerTraits<container>::KeyType;
const auto safeKey = reinterpret_cast<CKeyType>(key);
const bool valueExist = IsExists(container, safeKey);
if (!valueExists)
{
// generate some exception
}
return container.at(safeKey);
}
The problem here is ContainerTraits structure, because i need ability to pass container with ANY template parameters (the project use set of custom allocators etc.), so i wrote this:
template <typename CntT>
struct ContainerTraits;
template <typename ValT,
typename AllocT>
struct ContainerTraits<std::vector<ValT, AllocT>>
{
using KeyType = typename std::vector<ValT, AllocT>::size_type;
using ValType = typename std::vector<ValT, AllocT>::value_type;
};
template <typename KeyT,
typename ValT,
typename HashT,
typename KeyEqT,
typename AllocT>
struct ContainerTraits<std::unordered_map<KeyT, ValT, HashT, KeyEqT, AllocT>>
{
using KeyType = typename std::unordered_map<KeyT, ValT, HashT, KeyEqT, AllocT>::key_type;
using ValType = typename std::unordered_map<KeyT, ValT, HashT, KeyEqT, AllocT>::mapped_type;
};
But this doe not compile. So how can i specialize some template struct to pass for example std::map with any template arguments?
IsExists implementation:
template <typename ValT,
typename AllocT>
bool IsExistsImpl(const std::vector<ValT, AllocT>& vec,
const typename std::vector<ValT>::size_type& key)
{
return key < vec.size();
}
template <typename KeyT,
typename ValT,
typename HashT,
typename KeyEqT,
typename AllocT>
bool IsExistsImpl(const std::unordered_map<KeyT, ValT, HashT, KeyEqT, AllocT>& map, const KeyT& key)
{
return map.find(key) != map.end();
}
template <typename CntT, typename KeyT>
bool IsExists(const CntT& container, const KeyT& key)
{
return IsExistsImpl(container, key);
}
Upvotes: 0
Views: 123
Reputation: 25388
using CKeyType = ContainerTraits<container>::KeyType;
should instead be:
using CKeyType = ContainerTraits<CntT>::KeyType;
Also (typo):
const bool valueExist = IsExists(container, safeKey);
should be:
const bool valueExists = IsExists(container, safeKey);
But the most problematic line is this one:
const auto safeKey = reinterpret_cast<CKeyType>(key);
since:
CKeyType
is not const
CKeyType
is not a primitive typeThe best replacement seems to be:
const auto& safeKey = static_cast<const CKeyType &>(key);
although the restrictions of static_cast
may not suit your use case. reinterpret_cast
is too dangerous here.
Upvotes: 1