c++ - const-correctness of data-accessor types - better solution? -
i'm working on image-class makes possible work images different pixel layouts (rgb, rgba, gray, bayer, ...). access pixel it's possible call image.at<pixeltype>(x,y)
returns "accessor". concrete accessor-implementation dependent on template argument. i've ran issues regarding const correctness.
here dumbed down implementation makes apparent:
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; // accessor non-const accessor<false> a1 = img.at(0, 0); // accessor const... accessor<true> a2 = a1; // ... modifying value results in error a2.data = 42; // try convert accessor const non-const version // ... results in error accessor<false> a3 = a2; return 0; }
as can see there non-const , const implementation of at
method. depending on constness template argument of accessor set true
or false
. i've got 2 different types (const , non-const) per accessor/pixel type makes necessary write conversion constructor because otherwise test-cases shown in main()
function wouldn't work.
now question is: there better way achieve this? feels kind of bad use template argument const indicator. nicer use accessor
, const accessor
. on other hand similar std-library ::iterator
, ::const_iterator
. has experience such situations?
you can (over-)generalise parameter having 2 boolean states value type instead:
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; };
obviously isn’t different have, except under guise: instead of accessor<false>
, accessor<true>
, have accessor<datatype>
, accessor<datatype const>
.
the benefit familiarity: of e.g. std::unique_ptr<t>
, std::shared_ptr<t>
, std::reference_wrapper<t>
(and t*
) behave same way. in particular, famialiarity should extend compiler errors lack of conversion accessor<datatype const>
accessor<datatype>
, can’t convert int const*
int*
.
Comments
Post a Comment