2010-06-25 63 views
2

我有一个static std::map<std::string, CreateGUIFunc>在基本上持有字符串标识gui类型的类,CreateGUIFunc是对工厂函数的引用。std ::只读位置的地图分配

在我的构造函数中我有

if (m_factoryRef.size() == 0) { 
    m_factoryRef["image"] = &CreateGUI<Image>; 
    m_factoryRef["button"] = &CreateGUI<Button>; 
} 
... 

然而,这给了我一个错误说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>())))))))’|

我不知道为什么这是一个只读的分配。我也尝试将其更改为普通成员,以查看是否它可能是静态的,但同样的事情。

什么问题?

编辑:一些定义,以使事情多一点明确

// 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; 

附:如果有更清晰的方式来初始化静态地图请让我知道。

+2

你可以修改地图的定义,并添加CreateGUIFunc和CreateGUI的定义(不是完整的类,只是为了让我们看看它是什么),甚至更好的可能是最小的selfcontained程序的整个代码重现问题。 – nus 2010-06-26 00:10:59

+1

据我可以告诉你有模板和参考有点混在这里。 '&'前缀不是引用,但是如果我没有错误,则“操作符的地址”和“CreateGUI ”不是对象的有效名称。 – nus 2010-06-26 00:26:40

+1

如何声明'm_factoryRef'? – 2010-06-26 00:27:26

回答

0

在C++中,typedef GUI* CreateGUIFunc();不是具有未指定参数的函数,而是具有NO参数的函数。所以你的功能都不符合这种类型。你想要的是typedef GUI* (*CreateGUIFunc)(std::string &filepath, int x, int y);

接下来,尝试使用地图的insert成员函数而不是下标运算符,这样你就不会偶然调用常量版本。

+0

好的,我比解释函数指针有什么问题更接近我,但是在下标操作符上它应该起作用,如果它不起作用,那么除了事故之外,它不应该起作用... – nus 2010-06-26 00:53:21

1

以下是对当前C++的一些替代初始化。当你说你的代码在构造函数中时,我不确定你的意思是“静态”初始化。我有一些猜测,但没关系。选择对你来说“更清洁”的东西。

if (m.empty()){ 
    m.insert (map<K,V>::value_type (k1, v1)); 
    m.insert (map<K.V>::value_type (k1, v1)); 
} 

,或者

map<K,V>& getmap() { 
    static map<K,V>* m = 0; 
    if (!m){ 
     m = new map<K,V>(); // never deleted. 
     // insert. 
    } 
    return *m; 
} 

,或者

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(); 

,或者

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; 
} 

的图案应该是显而易见的。你必须解决两个问题:仅仅一次初始化该死的东西这个微不足道的问题,以及防止静态初始化命令失败的棘手问题。我的人的偏好就像上面的第二种情况。

+0

+1提供各种解决方案。我建议保持清除#1,并认为#2简单明了。值得注意的是,所有这些情况在多线程上下文中都很容易出现问题(如果Foo是第一次由两个线程同时构建的话)。 – stinky472 2010-06-26 02:00:24