如何避免const转换为地图访问?

Gab*_*iel 20 c++ stdmap c++11 c++14

我有以下问题:

std::map<A*,double> map;

void getColor(A const * obj){
    double d = map[obj]; // does not compile wihtout const_cast<A*>(obj)
    // do something
}
Run Code Online (Sandbox Code Playgroud)

我有一个地图std::map(某处)存储指向对象的指针A.我有一个操纵对象的函数getColor, 因此将指针 作为输入.Aconst A

如果getColor不使用const_cast ,函数将无法编译.

const cast是一个设计问题,但如果我不想map const中创建键,我不知道如何规避它.

任何帮助赞赏.

Rei*_*ica 19

这里有两种可能的情况:

  1. 该函数知道/期望obj已经存在于地图中,并且[]为方便起见而使用.

  2. 你正在[]充分利用它的潜力,即obj如果还没有它,你希望它添加到地图中.

在情境2中,getColor签名中存在错误.由于它可能会传递obj到它将被存储的地方,因此仅A*接受一个地方是错误的const A*.请注意,即使函数不修改对象本身但将其传递到可以修改的某个地方,它也会间接地对其进行修改,因此应将其视为非const.

在情况1中,它取决于您的C++版本.C++ 14引入一个的模板过载find和相关的成员函数的std::map这需要任何可比用Key而不是仅Key.因此,您可以像这样修改函数:

void getColor( A const * obj){
    doubel d = map.find(obj)->second;
    // do something
}
Run Code Online (Sandbox Code Playgroud)

请注意,要使其工作,您还需要更改地图的类型以使用透明比较器:( std::map<A*,double, std::less<>> map;首先由@Leon的回答指出).

如果你坚持使用C++ 11或更早版本,那么你运气不好,你将不得不忍受const_cast.请注意,通过合适的注释,a const_cast在这种情况下是完全安全且可接受的(更不用说在不改变类型的情况下继续进行的唯一方法map).同样,你应该使用find或者at代替[],因为你不想插入地图.

  • @Yakk有趣的事实:直到[最近](https://timsong-cpp.github.io/lwg-issues/2562),措辞实际上并不保证这些措辞所施加的总订单与部分订单一致内置插件或相互强加的:) (3认同)
  • @tc"有趣"的事实 (2认同)

Leo*_*eon 6

如果你能负担得起切换到C++ 14那么你可以配置你的地图使用透明比较器(这将工作,因为const指针可以与非const指针进行比较):

std::map<A*,double, std::less<>> map;
//                  ^^^^^^^^^^^
//                  enable transparent comparator on this map

void getColor( A const * obj){
    auto it = map.find(obj);
    assert(it != map.end());
    double d = it->second;
    // do something
}
Run Code Online (Sandbox Code Playgroud)

请注意,您必须使用std::map::find()而不是std::map::operator[],因为后者没有透明版本.