对象的代理,适当的const限定及其缺乏

Proxy to an object, proper const qualification and lack thereof

本文关键字:const 代理 对象      更新时间:2023-10-16

我刚刚发现了一些对我来说像是怪癖的东西

struct Tile {
    Tile(Map &map, int, int)
    : map(map) { }
    void destroy();
    void display() const;
    Map ↦
};

这个(精简的)类是一个访问器对象。它是由Map本身构造的:

Tile Map::operator ()(int x, int y) {
    return Tile(*this, x, y);
}
Tile const Map::operator ()(int x, int y) const {
    return Tile(*this, x, y);
}

因此,Map可以返回Tile,我们可以从中调用destroy()(更新映射),而Map const只能返回Tile const,我们只能从中调用非修改的display()方法。

所以一切都很好,对吧?不完全是这样。因为尽管一开始看起来很简单,但由于Map&构造函数参数的原因,我不知道如何从Map const构造Tile。

我还尝试删除Tile的构造函数并聚合初始化它,但没有成功:

Tile const Map::operator ()(int x, int y) const {
    return { *this, x, y };
}

这对我来说更奇怪,因为我得到了…

error: invalid initialization of reference of type ‘Map&’ from expression of type ‘const Map’

即使Tile const应该只包含const字段,不是吗?

为什么编译器会抱怨最后一个(第一个非常合乎逻辑),我可以做一些事情来重写整个Tile类专门用于const访问吗?它可能是const_cast正确的神话之地吗?

提前谢谢。

Daniel的做法是正确的-您肯定需要一个TileConstTile类,为了简单起见,可以对它们进行模板化,但您需要处理何时可以调用destroy()以及如何构造它们。为此:

template<class MapT>
struct TileT {
    TileT(MapT &map, int, int)
    : map(map) { }
    // we want to be able to construct ConstTile from Tile
    template <typename M>
    TileT(const TileT<M>& tile)
    : map(tile.map) { } 
    void destroy() {
        static_assert(!std::is_const<MapT>::value, "Cannot call destory() from ConstTile");
        // rest of implementation
    }
    void display() const;
    MapT &map;
};
using Tile = TileT<Map>;
using ConstTile = TileT<const Map>;

这将为您提供所需的功能,并且将以与iterator/const_iterator类似的方式工作。所以你可以做这样的事情:

Map map;
...
ConstTile tile = map(4,3); // non-const map, ConstTile is ok

我认为没有办法创建Tile类的两个版本:一个用于常量访问,另一个用于可变访问。考虑以下问题:如果Map引用是const,destroy函数应该怎么做?

如果你想绕过Tile和ConstTile版本的类,你可以使用模板来实现同样的效果,同时避免代码重复。

template<class MapT>
struct Tile {
    Tile(MapT &map, int, int)
    : map(map) { }
    template<typename U = MapT>
    std::enable_if<std::is_const<U>::value> destroy();
    void display() const;
    MapT &map;
};

MapT现在可以是Map或constMap,具体取决于实例化。