Calling the counting method std :: set of pointers with reference to the key type const

I have a class like

struct S { bool foo(const AType& v) const { return values.count(&v); // compile error due to the constness of v } private: std::set<AType*> values; }; 

This is a simplified version. In real code, foo does some tricky things. The code causes an error

 invalid conversion from 'const AType*' to 'std::set<AType*>::key_type {aka AType*}' 

I think foo should accept 'const AType & v' because it does not mutate v. The type of the member "value" variable cannot be std :: set <const AType *> because some methods of the S structure invoke non-constant methods of the elements contained in the "values". I can set the constant "v":

 bool foo(const AType& v) const { return values.count((AType*) &v); } 

But I think that this may not be a good solution in general. What solution can I get?

+5
source share
3 answers
 template<class T> struct const_ptr_compare:std::less<T const*> { typedef void is_transparent; }; std::set<AType*, const_ptr_compare<AType>> values; 

and Bob is your uncle.

I have defined a comparator that can transparently handle T const* comparisons as well as T* comparisons. Then I told std::set that it is transparent.

The is_transparent method is an upgrade from C ++ 14 to std::set . Your compiler may have support.


If you want to go to base-classes-of- T , a little more work is required. You need a function object that checks its two arguments (each points to const) to see what is the base class of the other, and uses std::less<base const*>{}(lhs, rhs) this base class. However, this goes further down the rabbit hole than we need.


The C ++ 11/03 approach may include creating editable parts of AType mutable and having const AType* set . Otherwise, a const_cast<AType*> is reasonable.

Please do not use the C-style: they are almost never required, and they can be too powerful.

0
source

The root of the problem is this:

The type of the member "value" variable cannot be std :: set because some struct S methods call non-constant methods on the elements contained in the "values".

You must not mutate the installation key in any way.

You should use map , where the actual key parts are in the key and const , and the mutating parts are in the value and are not const .

If this is not practical for your design, I understand. The const_cast will solve the problem. It feels inelegant, but that is because your use of set inelegant.

0
source

This is just one of many problems in the concept of constant correctness: it does not scale in composition.

The casting solution is fine, if you think it is dirty, you might overestimate the purity of the concept of const .

Note that it was necessary to define special types for const_iterator and const_reverse_iterator or that sometimes constant correctness requires actual code duplication (for example, in many cases for operator[] ) or that if you have an object that does not contain a const pointer, you can freely mutate the object pointing to an object, and even delete it in constant members.

Your throw doesn't look so bad in comparison :-)

0
source

Source: https://habr.com/ru/post/1205216/


All Articles