数据管理员类型的const校正性 - 更好的解决方案

const-correctness of data-accessor types - better solution?

本文关键字:更好 解决方案 const 数据管理 管理员 类型 数据      更新时间:2023-10-16

我正在研究图像类,这使得可以使用具有不同像素布局的图像(RGB,RGBA,Gray,Gray,Bayer,...)。要访问像素,可以调用返回"登录器"的image.at<PixelType>(x,y)。混凝土登录器 - 实现取决于模板参数。但是现在我遇到了一些有关const正确性的问题。

这是一个非常愚蠢的实现,希望很明显:

template<bool constAccessor>
class Accessor {
public:
    typedef typename boost::mpl::if_c<constAccessor, const int, int>::type DataType;
    Accessor(DataType& data) 
    :data(data) {
    }
    Accessor(Accessor<false>& other) 
    : data(other.data) {
    }
    DataType& data;
};

class Image {
public:
    Accessor<false> at(unsigned int x, unsigned int y) {
        return Accessor<false>(data);
    }
    Accessor<true> at(unsigned int x, unsigned int y) const {
        return Accessor<true>(data);
    }
private:
    int data;
};
int main() {
    Image img;
    const Image& cimg = img;
    // get accessor which is non-const
    Accessor<false> a1 = img.at(0, 0); 
    // get a accessor which is const...
    Accessor<true> a2 = a1;
    // ... modifying a value results in an error
    a2.data = 42;
    // try to convert a accessor which is const to a non-const version
    // ... results in an error
    Accessor<false> a3 = a2;
    return 0;
}

您可以看到at方法的非const和const实现。取决于宪法,将登录器的模板参数设置为truefalse。但是现在,我每个登录/像素类型有两种不同的类型(const和non-const),这使得有必要编写转换构造函数,因为否则main()函数中显示的测试箱将不起作用。

现在的问题是:有更好的方法可以实现这一目标吗?将模板参数用作const指示器感觉有些不好。只使用Accessorconst Accessor会更好。另一方面,这与::iterator::const_iterator的STD图书馆所做的类似。任何人都有这种情况的经验?

您可以(过度)从将两个布尔态概括到任何值类型的参数:

template<typename Value>
class Accessor {
public:    
    Accessor(Value& data) 
        : data(data)
    {}
    template<typename T, EnableIf<std::is_convertible<T&, Value&>>...>
    Accessor(Accessor<T> const& other)
        : data(other.data)
    {}
    Value& data;
};

显然,这与您所拥有的没有什么不同,除了其他伪装之外:而不是Accessor<false>Accessor<true>,您有Accessor<DataType>Accessor<DataType const>

好处是熟悉:例如std::unique_ptr<T>std::shared_ptr<T>std::reference_wrapper<T>(甚至T*)的行为方式相同。特别是,这种著名行为应希望扩展到编译器错误,内容涉及从Accessor<DataType const>转换为Accessor<DataType>,就像您无法从int const*转换为int*