Rachus: Wann ist ein const_cast angebracht?

Beitrag lesen

Hallo,

so funktioniert es (zumindest bei mir) nicht. Ich habe einmal die Klasse auf das nötigste heruntergebrochen:

#include <string>
#include <vector>
#include <list>
#include <unordered_map>

template
<
class Key = std::string,
class Value = std::string,
class Hash = std::hash<Key>,
class Equals = std::equal_to<Key>

class UM_Wrapper
{
public:
typedef Key key_type;
typedef Value value_type;
typedef Hash hasher_type;
typedef Equals equals_type;

	inline const bool key\_exists(const Key& key) const;  
	  
	private:  
	  
	class Hasher  
	{  
		public:  
			inline size\_t operator() (const Key\* const key) const;  
		private:  
			Hash hasher;  
	};  
	  
	class Equaler  
	{  
		public:  
			inline bool operator() (const Key\* const first, const Key\* const second) const;  
		private:  
			Equals equaler;  
	};  
	  
	std::list<Key> identifiers;  
	std::unordered\_multimap<Key\*, std::pair<class std::list<Key>::iterator, Value>, Hasher, Equaler> data;  

};

template<class Key, class Value, class Hash, class Equals>
inline const bool
UM_Wrapper<Key, Value, Hash, Equals>::key_exists(const Key& key) const
{
const Key* const_key = &key;
return data.find(const_key) != data.end();
}

template<class Key, class Value, class Hash, class Equals>
inline size_t
UM_Wrapper<Key, Value, Hash, Equals>::Hasher::operator()
(const Key* const key) const
{
return hasher(*key);
}

template<class Key, class Value, class Hash, class Equals>
inline bool
UM_Wrapper<Key, Value, Hash, Equals>::Equaler::operator()
(const Key* const first, const Key* const second) const
{
return equaler(*first, *second);
}

Um zu "testen", habe ich mir dann noch eine kleine main-Funktion geschrieben.

#include "um_wrapper.hpp"
#include <iostream>

int main()
{
UM_Wrapper<> w;
w.key_exists("keystring");
return 0;
}

Kompiliert wurde es per "g++ -std=c++0x tester.cpp". Dabei fliegt mir folgende Fehlermeldung um die Ohren.

In file included from tester.cpp:1:0:
um_wrapper.hpp: In instantiation of ‘const bool UM_Wrapper<Key, Value, Hash, Equals>::key_exists(const Key&) const [with Key = std::basic_string<char>; Value = std::basic_string<char>; Hash = std::hash<std::basic_string<char> >; Equals = std::equal_to<std::basic_string<char> >]’:
tester.cpp:7:26:   required from here
um_wrapper.hpp:51:42: error: passing ‘const std::unordered_multimap<std::basic_string<char>*, std::pair<std::_List_iterator<std::basic_string<char> >, std::basic_string<char> >, UM_Wrapper<>::Hasher, UM_Wrapper<>::Equaler, std::allocator<std::pair<std::basic_string<char>* const, std::pair<std::_List_iterator<std::basic_string<char> >, std::basic_string<char> > > > >’ as ‘this’ argument of ‘std::_Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, __cache_hash_code, __constant_iterators, __unique_keys>::iterator std::_Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, __cache_hash_code, __constant_iterators, __unique_keys>::find(const key_type&) [with _Key = std::basic_string<char>*; _Value = std::pair<std::basic_string<char>* const, std::pair<std::_List_iterator<std::basic_string<char> >, std::basic_string<char> > >; _Allocator = std::allocator<std::pair<std::basic_string<char>* const, std::pair<std::_List_iterator<std::basic_string<char> >, std::basic_string<char> > > >; _ExtractKey = std::_Select1st<std::pair<std::basic_string<char>* const, std::pair<std::_List_iterator<std::basic_string<char> >, std::basic_string<char> > > >; _Equal = UM_Wrapper<>::Equaler; _H1 = UM_Wrapper<>::Hasher; _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; bool __cache_hash_code = true; bool __constant_iterators = false; bool __unique_keys = false; std::_Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, __cache_hash_code, __constant_iterators, __unique_keys>::iterator = std::__detail::_Node_iterator<std::pair<std::basic_string<char>* const, std::pair<std::_List_iterator<std::basic_string<char> >, std::basic_string<char> > >, false, true>; std::_Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, __cache_hash_code, __constant_iterators, __unique_keys>::key_type = std::basic_string<char>*]’ discards qualifiers [-fpermissive]
um_wrapper.hpp:51:42: error: invalid conversion from ‘const std::basic_string<char>*’ to ‘std::_Hashtable<std::basic_string<char>*, std::pair<std::basic_string<char>* const, std::pair<std::_List_iterator<std::basic_string<char> >, std::basic_string<char> > >, std::allocator<std::pair<std::basic_string<char>* const, std::pair<std::_List_iterator<std::basic_string<char> >, std::basic_string<char> > > >, std::_Select1st<std::pair<std::basic_string<char>* const, std::pair<std::_List_iterator<std::basic_string<char> >, std::basic_string<char> > > >, UM_Wrapper<>::Equaler, UM_Wrapper<>::Hasher, std::__detail::_Mod_range_hashing, std::__detail::_Default_ranged_hash, std::__detail::_Prime_rehash_policy, true, false, false>::key_type {aka std::basic_string<char>*}’ [-fpermissive]
In file included from /usr/include/c++/4.7/unordered_map:45:0,
                 from um_wrapper.hpp:5,
                 from tester.cpp:1:
/usr/include/c++/4.7/bits/hashtable.h:932:5: error:   initializing argument 1 of ‘std::_Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, __cache_hash_code, __constant_iterators, __unique_keys>::iterator std::_Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, __cache_hash_code, __constant_iterators, __unique_keys>::find(const key_type&) [with _Key = std::basic_string<char>*; _Value = std::pair<std::basic_string<char>* const, std::pair<std::_List_iterator<std::basic_string<char> >, std::basic_string<char> > >; _Allocator = std::allocator<std::pair<std::basic_string<char>* const, std::pair<std::_List_iterator<std::basic_string<char> >, std::basic_string<char> > > >; _ExtractKey = std::_Select1st<std::pair<std::basic_string<char>* const, std::pair<std::_List_iterator<std::basic_string<char> >, std::basic_string<char> > > >; _Equal = UM_Wrapper<>::Equaler; _H1 = UM_Wrapper<>::Hasher; _H2 = std::__detail::_Mod_range_hashing; _Hash = std::__detail::_Default_ranged_hash; _RehashPolicy = std::__detail::_Prime_rehash_policy; bool __cache_hash_code = true; bool __constant_iterators = false; bool __unique_keys = false; std::_Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, __cache_hash_code, __constant_iterators, __unique_keys>::iterator = std::__detail::_Node_iterator<std::pair<std::basic_string<char>* const, std::pair<std::_List_iterator<std::basic_string<char> >, std::basic_string<char> > >, false, true>; std::_Hashtable<_Key, _Value, _Allocator, _ExtractKey, _Equal, _H1, _H2, _Hash, _RehashPolicy, __cache_hash_code, __constant_iterators, __unique_keys>::key_type = std::basic_string<char>*]’ [-fpermissive]

Wie bereits beschrieben, würde es nunmal mit einem
return data.find(const_cast<Key*>(&key)) != data.end();
funktionieren. Aber da ist eben dieser Cast drin, der theoretisch von einem schlechten Konzept zeugt.

Hoffentlich sind jetzt alle Klarheiten beseitigt ;)

Grüße,

Rachus