I have a static std::map<std::string, CreateGUIFunc>
in a class that basically holds strings identifying gui types, and CreateGUIFunc is a reference to a factory function.
In my constructor I have
if ( m_factoryRef.size() == 0 ) {
m_factoryRef["image"] = &CreateGUI<Image>;
m_factoryRef["button"] = &CreateGUI<Button>;
}
...
However, this gives me an error saying assignment of read-only location ‘GUIManager::m_factoryRef.std::map<_Key, _Tp, _Compare, _Alloc>::operator[] [with _Key = std::basic_string<char, std::char_traits<char>, std::allocator<char> >, _Tp = GUI*(), _Compare = std::less<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, _Alloc = std::allocator<std::pair<const std::basic_string<char, std::char_traits<char>, std::allocator<char> >, GUI*()> >](((const std::basic_string<char, std::char_traits<char>, std::allocator<char> >&)(& std::basic_string<char, std::char_traits<char>, std::allocator<char> >(((const char*)"image"), ((const std::allocator<char>&)((const开发者_如何学编程 std::allocator<char>*)(& std::allocator<char>())))))))’|
I'm not sure why this is a read-only assignment. I also tried changing it to a normal member just to see if maybe it had to do with it being static, but same thing.
What is the problem?
Edit: Some definitions to make things a bit more clear
// these are all private
typedef GUI* CreateGUIFunc();
template<class T>
GUI* GUIManager::CreateGUI( std::string &filepath, int x, int y ) {
return new T( filepath, x, y );
}
static std::map<std::string, CreateGUIFunc> m_factoryRef;
P.S. If there is any cleaner way to initialize a static map please let me know.
Here are some alternative initializations for current C++. I'm not sure what you mean by "static" initialization when you said your code is in a constructor. I have some guesses, but it doesn't matter. Choose what feels "cleaner" to you.
if (m.empty()){
m.insert (map<K,V>::value_type (k1, v1));
m.insert (map<K.V>::value_type (k1, v1));
}
or,
map<K,V>& getmap() {
static map<K,V>* m = 0;
if (!m){
m = new map<K,V>(); // never deleted.
// insert.
}
return *m;
}
or,
namespace /*anon*/ {
map<K,V>* init_map () {
map<K,V>* m = new map<K,V>();
// insertions here.
return m; // return by val. can move in c++0x.
}
}
map<K,V> Foo::m = *init_map ();
or,
namespace /*anon*/ {
map<K,V>* init_map () {
map<K,V>* m = new map<K,V>();
// insertions here.
return m; // return by val. can move in c++0x.
}
}
map<K,V>& Foo::get_map () { /* static singleton accessor */
static map<K,V> * m = init_map ();
return *m;
}
The pattern should be obvious. You have to solve two problems: the trivial problem of initializing the damn thing only once, and the trickier problem of preventing the static initialization order fiasco. My person preference is something like the second case above.
In C++, typedef GUI* CreateGUIFunc();
isn't a function with unspecified parameters, it's a function with NO parameters. So none of your functions match that type. What you want is typedef GUI* (*CreateGUIFunc)( std::string &filepath, int x, int y );
Next, try using the insert
member function of the map instead of the subscript operator, that way you can't end up calling the constant version by accident.
精彩评论