2012-02-20 64 views
2

我想做一个包装std :: map的类,并检查以确保这些键是已批准的有效字符串的一个,并且还初始化了映射所有批准的有效字符串的默认值。我有问题让下标操作工作,特别是它的常量版本。用std :: map成员变量的类的下标运算符

这里是我的类原型代码:

#include <set> 
#include <string> 
#include <map> 

class foo { 
    public: 
    foo() {} 
    const double & operator[](const std::string key) const { 
     return data[key]; 
    } 
    private: 
    static const std::set<std::string> validkeys; 
    std::map<std::string, double> data; 
}; 

const std::set<std::string> foo::validkeys = {"foo1", "foo2"}; 

当我编译这个(使用G ++与-std = C++ 0x中),我得到这个编译错误:

|| /home/luke/tmp/testmap.cc: In member function 'double& foo::operator[](std::string) const': 
testmap.cc|10 col 22 error| passing 'const std::map<std::basic_string<char>, double>' as 
'this' argument of 'mapped_type& std::map<_Key, _Tp, _Compare, _Alloc>::operator[](const 
key_type&) [with _Key = std::basic_string<char>, _Tp = double, _Compare = 
std::less<std::basic_string<char> >, _Alloc = std::allocator<std::pair<const 
std::basic_string<char>, double> >, mapped_type = double, key_type = 
std::basic_string<char>]' discards qualifiers 

没有我似乎解决这个问题。我曾尝试

  • 使validkeys一个std ::设置和数据的std ::地图
  • 使用为const char *而不是字符串
  • 返回常量双或双,而不是常量双&
  • 使用列表和向量而不是设置存储有效的键

我不知道我是否正确地接近这个问题,所以如果有其他简单的方法来创建一个类,允许这种类型的f性感:

foo a; 
a["foo2"] = a["foo1"] = 5.0; 
// This would raise a std::runtime_error because I would be checking that 
// "foo3" isn't in validkeys 
a["foo3"] = 4.0; 

任何建议非常感谢。

SOLUTION

下面的工作正是我想要它,我甚至有一个基本的异常,当您尝试设置或一键搞定,是不是在一组有效键:

#include <iostream> 
#include <string> 
#include <map> 
#include <set> 
#include <stdexcept> 

class myfooexception : public std::runtime_error 
{ 
    public: 
    myfooexception(const std::string & s) 
     : std::runtime_error(s + " is not a valid key.") {} 
}; 

class foo { 
    public: 
    foo() { 
    for (std::set<std::string>::iterator it = validkeys.begin(); 
      it != validkeys.end(); 
      ++it) { 
     data[*it] = 0.0; 
    } 
    } 
    const double & operator[](const std::string & key) const { 
     if (data.find(key) == data.end()) { 
     throw myfooexception(key); 
     } else { 
     return data.find(key)->second; 
     } 
    } 
    double & operator[](const std::string & key) { 
     if (data.find(key) == data.end()) { 
     throw myfooexception(key); 
     } else { 
     return data[key]; 
     } 
    } 
    private: 
    static const std::set<std::string> validkeys; 
    std::map<std::string, double> data; 
}; 

const std::set<std::string> foo::validkeys = {"foo1", "foo2"}; 

int main(void) 
{ 
    foo a; 
    a["foo1"] = 2.0; 
    a["foo1"] = a["foo2"] = 1.5; 
    // a["foo3"] = 2.3; // raises exception: foo3 is is not a valid key 
    const foo b; 
    std::cout << b["foo1"]; // should be ok 
    // b["foo1"] = 5.0; // compliation error, as expected: b is const. 

    return 0; 
} 
+0

你为什么要做2次扫描的地图?您可以使用'find'并检查其结果 – davka 2012-02-20 08:06:46

+0

谢谢。我将其更改为if(data.find(key)== data。结束()) – hazelnusse 2012-02-20 08:42:38

+1

你还在做两次:) – davka 2012-02-20 11:16:51

回答

0

您试图分配给std::map但你的函数声明const也返回const。删除这两个const它应该工作。

1

你正试图修改一个const对象! 请删除set.const成员的const在初始化后无法修改。

+0

如果你指的是'静态常量的std ::设置 validkeys;',这是合法的C++ - 这是你如何初始化静态常量成员变量。 – hazelnusse 2012-02-20 07:52:55

2

std::map的下标运算符是非常量,因为它插入了一个新的元素(如果还不存在)。如果你想要你的地图有一个const operator[],你需要编写一个使用map::find()map::end()的测试,处理错误情况。

+0

谢谢,这个作品。我使用map :: count(key)来检查密钥是否存在。看到我上面的解决方案 – hazelnusse 2012-02-20 07:49:19

+0

如果您使用您正在搜索的两倍'地图::计数()'。 – 2012-02-20 08:20:22

+0

谢谢。我把它改为'如果(data.find(键)== data.end())' – hazelnusse 2012-02-20 08:40:59

3

operator []未声明在std::mapconst,因为operator []还插入当钥匙没有找到新的元素,并返回到它的映射值的引用。如果您希望operator[]const,则可以使用map::find方法代替map::operator[]

+0

感谢您的答复,地图::找到工作。 – hazelnusse 2012-02-20 08:49:35