Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++: find in set of pointers

My problem is illustrated by following example:

#include <set>

class A {};

int main()
{
    A a;
    A * p = &a;
    const A * cp = &a;

    std::set<A*> s;
    s.insert(p);
    s.find(cp);
}

Compilation ends in:

a.cpp: In function ‘int main()’:
a.cpp:13:18: error: invalid conversion from ‘const A*’ to ‘std::set<A*>::key_type {aka A*}’ [-fpermissive]
         s.find(cp);
                  ^
In file included from /usr/include/c++/4.9.1/set:61:0,
                 from a.cpp:1:
/usr/include/c++/4.9.1/bits/stl_set.h:701:7: note: initializing argument 1 of ‘std::set<_Key, _Compare, _Alloc>::iterator std::set<_Key, _Compare, _Alloc>::find(const key_type&) [with _Key = A*; _Compare = std::less<A*>; _Alloc = std::allocator<A*>; std::set<_Key, _Compare, _Alloc>::iterator = std::_Rb_tree_const_iterator<A*>; std::set<_Key, _Compare, _Alloc>::key_type = A*]’
       find(const key_type& __x)

I know why it does not compile, but is there any solution less ugly and brutal than s.find((A*)cp)? Both set and const pointer are given.

like image 613
Dekakaruk Avatar asked Sep 16 '14 21:09

Dekakaruk


Video Answer


2 Answers

An option is to use C++14 transparent operator functors together with heterogeneous lookup:

std::set<A*, std::less<>> s;
s.find(cp);

Unfortunately, heterogeneous lookup is not currently supported in libstdc++, but it's marked as WIP. (It's available in clang/libc++ and will be available in the next version of Visual Studio.) Without it, you are pretty much stuck with const_cast'ing cp.

like image 125
T.C. Avatar answered Sep 18 '22 12:09

T.C.


Tragically, set's querying methods aren't templated on the key type (they really should be), so lower_bound, equal_range, etc. won't help.

Your only options, assuming that the variable types aren't negotiable, are to cast away the pointer's constness, or reinterpret_cast the set to a set<const A*>. The latter in some ways feels nicer to me, but it's technically unsafe.

Cast away the constness. Use const_cast to do it, to make it clear that that's the only thing the cast is doing. If you like, wrap that and the find in a free function; if a piece of code is being evil, it's a good idea to make the evil thing the only thing it does.

like image 30
Sneftel Avatar answered Sep 20 '22 12:09

Sneftel