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

时间:2014-10-30 22:36:08

标签: c++ c++11 reference const c++14

我刚刚发现了一些看起来像是怪癖的东西。考虑一下:

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 const构造函数参数,我无法弄清楚如何从Map&构造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个字段,不应该吗?

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

提前致谢。

2 个答案:

答案 0 :(得分:3)

丹尼尔走在正确的轨道上 - 你肯定需要一个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

答案 1 :(得分:2)

我认为没有办法创建两个版本的Tile类:一个用于const访问,一个用于可变访问。请考虑以下内容:如果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或const Map,具体取决于实例化。