Dekakaruk
Dekakaruk

Reputation: 717

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.

Upvotes: 12

Views: 2813

Answers (3)

T.C.
T.C.

Reputation: 137310

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.

Upvotes: 10

Christophe
Christophe

Reputation: 73366

You could use find with a const_cast:

s.find(const_cast<A*>(cp));

Upvotes: 2

Sneftel
Sneftel

Reputation: 41474

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.

Upvotes: 2

Related Questions