I'm trying to use a boost::bimap to provide bi-directional mapping of some node numbers. I have been using boost unordered maps for a few other things, and have no problems using them. I'm on visual studio 2010.
However I get a ton of template errors whenever I try and use a bimap. Even cutting and pasting the code from the examples at here I get the same masses of template problems. E.g: I inserted this code, direct from the examples:
typedef boost::bimap< int, std::string > bm_type;
bm_type bm;
bm.insert( bm_type::value_type(1, "one" ) );
bm.insert( bm_type::value_type(2, "two" ) );
and I get about 750 lines of errors, starting with this:
c:\data\boost\boost_1_56_0\boost\bimap\relation\mutant_relation.hpp(94): error C2220: warning treated as error - no 'object' file generated
1> c:\data\boost\boost_1_56_0\boost\bimap\relation\mutant_relation.hpp(157) : see reference to class template instantiation 'boost::bimaps::relation::detail::relation_storage<LeftType,RightType,force_mutable>' being compiled
1> with
1> [
1> LeftType=boost::bimaps::tags::tagged<const int,boost::bimaps::relation::member_at::left>,
1> RightType=boost::bimaps::tags::tagged<const std::basic_string<char,std::char_traits<char>,std::allocator<char>>,boost::bimaps::relation::member_at::right>,
1> force_mutable=false
1> ]
and ending in
IteratorToBaseConverter=boost::bimaps::container_adaptor::support::iterator_facade_to_base<boost::bimaps::detail::map_view_iterator<boost::bimaps::relation::member_at::right,boost::bimaps::detail::bimap_core<int,std::string,boost::mpl::na,boost::mpl::na,boost::mpl::na>>,boost::bimaps::detail::const_map_view_iterator<boost::bimaps::relation::member_at::right,boost::bimaps::detail::bimap_core<int,std::string,boost::mpl::na,boost::mpl::na,boost::mpl::na>>>,
1> IteratorFromBaseConverter=boost::mpl::na,
1> ReverseIteratorFromBaseConverter=boost::mpl::na,
1> ValueToBaseConverter=boost::bimaps::relation::detail::pair_to_relation_functor<boost::bimaps::relation::member_at::right,boost::bimaps::relation::mutant_relation<boost::bimaps::tags::tagged<const int,boost::bimaps::relation::member_at::left>,boost::bimaps::tags::tagged<const std::basic_string<char,std::char_traits<char>,std::allocator<char>>,boost::bimaps::relation::member_at::right>,boost::bimaps::detail::manage_additional_parameters<boost::mpl::na,boost::mpl::na,boost::mpl::na>::case_NNN::additional_info,true>>,
1> ValueFromBaseConverter=boost::bimaps::relation::support::get_pair_functor<boost::bimaps::relation::member_at::right,boost::bimaps::relation::mutant_relation<boost::bimaps::tags::tagged<const int,boost::bimaps::relation::member_at::left>,boost::bimaps::tags::tagged<const std::basic_string<char,std::char_traits<char>,std::allocator<char>>,boost::bimaps::relation::member_at::right>,boost::bimaps::detail::manage_additional_parameters<boost::mpl::na,boost::mpl::na,boost::mpl::na>::case_NNN::additional_info,true>>
1> ]
1>c:\data\my_code.cpp(194): error C2665: 'boost::bimaps::relation::mutant_relation<TA,TB,Info,force_mutable>::mutant_relation' : none of the 5 overloads could convert all the argument types
1> with
1> [
1> TA=boost::bimaps::tags::tagged<const int,boost::bimaps::relation::member_at::left>,
1> TB=boost::bimaps::tags::tagged<const std::basic_string<char,std::char_traits<char>,std::allocator<char>>,boost::bimaps::relation::member_at::right>,
1> Info=boost::bimaps::detail::manage_additional_parameters<boost::mpl::na,boost::mpl::na,boost::mpl::na>::case_NNN::additional_info,
1> force_mutable=false
1> ]
1> c:\data\boost\boost_1_56_0\boost\bimap\relation\mutant_relation.hpp(265): could be 'boost::bimaps::relation::mutant_relation<TA,TB,Info,force_mutable>::mutant_relation(const int,const std::basic_string<_Elem,_Traits,_Ax> &)'
1> with
1> [
1> TA=boost::bimaps::tags::tagged<const int,boost::bimaps::relation::member_at::left>,
1> TB=boost::bimaps::tags::tagged<const std::basic_string<char,std::char_traits<char>,std::allocator<char>>,boost::bimaps::relation::member_at::right>,
1> Info=boost::bimaps::detail::manage_additional_parameters<boost::mpl::na,boost::mpl::na,boost::mpl::na>::case_NNN::additional_info,
1> force_mutable=false,
1> _Elem=char,
1> _Traits=std::char_traits<char>,
1> _Ax=std::allocator<char>
1> ]
1> while trying to match the argument list '(int, int)'
The same code on a linux machine compiles without errors. Any help most appreciated!
As noted in the comments below, the line
boost::bimap< int, std::string > test;
on its own will trigger similar errors. Ignore the error above regarding (int, int), I had left an earlier line in the code which was using a boost::bimap. Now removed, no significant change in the volume of errors.
Related
The following piece of code throwing warning C4800: 'int' : forcing value to bool 'true' or 'false' (performance warning). Moving #define true and false after string and map header inclusions not throwing this warning. This is a sample code and in the actual code #define true and false are defined in one of our product library header files. So I want to understand why this warning is thrown by visual studio and why it is going away when #define moved after string and map header inclusions.
#ifndef true
#define true 1
#endif
#ifndef false
#define false 0
#endif
#include <string>
#include <map>
int main()
{
std::map<std::string, std::string> pair;
pair.insert(std::make_pair("Key1", "Value1"));
return 0;
}
Full details of warning:
C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\utility(144): warning C4800: 'int' : forcing value to bool 'true' or 'false' (performance warning)
1> C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xtree(1801) : see reference to function template instantiation 'std::pair<std::_Tree_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<const _Kty,_Ty>>>>,bool>::pair<std::_Tree_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<const _Kty,_Ty>>>>,int,void>(_Other1 &&,_Other2 &&)' being compiled
1> with
1> [
1> _Kty=std::string
1> , _Ty=std::string
1> , _Other1=std::_Tree_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<const std::string,std::string>>>>
1> , _Other2=int
1> ]
1> C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xtree(1801) : see reference to function template instantiation 'std::pair<std::_Tree_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<const _Kty,_Ty>>>>,bool>::pair<std::_Tree_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<const _Kty,_Ty>>>>,int,void>(_Other1 &&,_Other2 &&)' being compiled
1> with
1> [
1> _Kty=std::string
1> , _Ty=std::string
1> , _Other1=std::_Tree_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<const std::string,std::string>>>>
1> , _Other2=int
1> ]
1> C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xtree(1160) : see reference to function template instantiation 'std::pair<std::_Tree_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<const _Kty,_Ty>>>>,bool> std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>::_Insert_nohint<std::pair<const _Kty,_Ty>&,std::_Tree_node<std::pair<const _Kty,_Ty>,void *>*>(bool,_Valty,_Nodety)' being compiled
1> with
1> [
1> _Kty=std::string
1> , _Ty=std::string
1> , _Pr=std::less<std::string>
1> , _Alloc=std::allocator<std::pair<const std::string,std::string>>
1> , _Valty=std::pair<const std::string,std::string> &
1> , _Nodety=std::_Tree_node<std::pair<const std::string,std::string>,void *> *
1> ]
1> C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\include\xtree(1160) : see reference to function template instantiation 'std::pair<std::_Tree_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<const _Kty,_Ty>>>>,bool> std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>::_Insert_nohint<std::pair<const _Kty,_Ty>&,std::_Tree_node<std::pair<const _Kty,_Ty>,void *>*>(bool,_Valty,_Nodety)' being compiled
1> with
1> [
1> _Kty=std::string
1> , _Ty=std::string
1> , _Pr=std::less<std::string>
1> , _Alloc=std::allocator<std::pair<const std::string,std::string>>
1> , _Valty=std::pair<const std::string,std::string> &
1> , _Nodety=std::_Tree_node<std::pair<const std::string,std::string>,void *> *
1> ]
1> Source.cpp(41) : see reference to function template instantiation 'std::pair<std::_Tree_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<const _Kty,_Ty>>>>,bool> std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>::insert<std::pair<const char *,const char *>>(_Valty &&)' being compiled
1> with
1> [
1> _Kty=std::string
1> , _Ty=std::string
1> , _Pr=std::less<std::string>
1> , _Alloc=std::allocator<std::pair<const std::string,std::string>>
1> , _Valty=std::pair<const char *,const char *>
1> ]
1> Source.cpp(41) : see reference to function template instantiation 'std::pair<std::_Tree_iterator<std::_Tree_val<std::_Tree_simple_types<std::pair<const _Kty,_Ty>>>>,bool> std::_Tree<std::_Tmap_traits<_Kty,_Ty,_Pr,_Alloc,false>>::insert<std::pair<const char *,const char *>>(_Valty &&)' being compiled
1> with
1> [
1> _Kty=std::string
1> , _Ty=std::string
1> , _Pr=std::less<std::string>
1> , _Alloc=std::allocator<std::pair<const std::string,std::string>>
1> , _Valty=std::pair<const char *,const char *>
1> ]
I'm not condoning your macros, but the answer to your question is that your check isn't nearly complete. In C++, true and false are keywords, not macros like in C's stdbool.h header. So checking if they aren't defined is always going to be true. If you want to C++-proof those macros, the condition should be something like this:
#if !defined(__cplusplus) && !defined(true)
#define true 1
#endif
__cplusplus is a standard macro that is defined by the implementation when a TU is compiled as C++. The added check will prevent messing up with those keywords, and breaking any standard library headers that use them.
You say
the #defines are declared in one of our product header files(not written by me)
Then, you should tell the guy who wrote this code to modify it. It's probably pure C code (where true/false are not defined) and he decided to declare them, why not, but then, I thing the good strategy would be for him not to use the standard names true/false that end up confliciting with standard ones in your case. He should use MyTrue/MyFalse (or whetever name that would make sense in the context).
So just (or ask him to) go in the code where true/false was defined, replace all occurence of "true" by "MyTrue", all "false" by "MyFalse", the code behaviour should not be impacted. The conflict will go away as well as the warning!
I am using VS2012 and I have problem with following example:
#include <chrono>
#include <thread>
int main()
{
// doesn't compile and I don't understand why:
std::this_thread::sleep_for(std::chrono::duration<double>(0.1));
// I can use this but still I would like to know the reason:
std::this_thread::sleep_for(std::chrono::duration<long long, std::milli>(100));
return 0;
}
Both duration should be valid. And it is possible to use them in different context.
Compile error:
1>c:\program files (x86)\microsoft visual studio 11.0\vc\include\chrono(749): error C2679: binary '+=' : no operator found which takes a right-hand operand of type 'const std::chrono::duration<_Rep>' (or there is no acceptable conversion)
1> with
1> [
1> _Rep=double
1> ]
1> c:\program files (x86)\microsoft visual studio 11.0\vc\include\chrono(166): could be 'std::chrono::duration<_Rep,_Period> &std::chrono::duration<_Rep,_Period>::operator +=(const std::chrono::duration<_Rep,_Period> &)'
1> with
1> [
1> _Rep=__int64,
1> _Period=std::nano
1> ]
1> while trying to match the argument list '(std::chrono::nanoseconds, const std::chrono::duration<_Rep>)'
1> with
1> [
1> _Rep=double
1> ]
1> c:\program files (x86)\microsoft visual studio 11.0\vc\include\thread(164) : see reference to function template instantiation 'xtime std::_To_xtime<double,std::ratio<_Nx>>(const std::chrono::duration<_Rep> &)' being compiled
1> with
1> [
1> _Nx=0x01,
1> _Rep=double
1> ]
1> i:\prog\.c++\test2\test2\source.cpp(13) : see reference to function template instantiation 'void std::this_thread::sleep_for<double,std::ratio<_Nx>>(const std::chrono::duration<_Rep> &)' being compiled
1> with
1> [
1> _Nx=0x01,
1> _Rep=double
1> ]
1>
1>Build FAILED.
Any help appreciated.
It is VS2012 compiler issue. Not 100% sure if it is this one (thx Praetorian). But it is possible to compile without problem with gcc 4.9.2. I should've think about trying it before I ask.
The Problem
Consider the following vectors:
std::vector<std::string> extensions;
extensions.push_back(".cpp");
extensions.push_back(".CPP");
extensions.push_back(".h");
extensions.push_back(".H");
std::vector<std::string> caselessUniqueExtensions;
Copy the contents of extensions into caselessUniqueExtensions, but discard all unique extensions, ignoring case. (I.e. the result should have two elements - one of either .cpp or .CPP, and one of either .h and .H.)
The Question
There are obviously many ways to do this, some more effecient than others, and some more readable than others. One such way I thought may work is the following:
#include <boost/algorithm/string/compare.hpp>
...
std::unique_copy(
extensions.begin(), extensions.end(),
caselessUniqueExts.begin(),
boost::is_iequal());
However, it fails to compile using MSVS2010:
1>c:\program files (x86)\microsoft visual studio 10.0\vc\include\xlocale(626): error C2440: 'type cast' : cannot convert from 'unsigned char' to 'std::basic_string<_Elem,_Traits,_Ax>'
1> with
1> [
1> _Elem=char,
1> _Traits=std::char_traits<char>,
1> _Ax=std::allocator<char>
1> ]
1> No constructor could take the source type, or constructor overload resolution was ambiguous
1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\xlocale(2211) : see reference to function template instantiation '_Elem std::_Maklocchr<_Elem>(char,_Elem *,const std::_Locinfo::_Cvtvec &)' being compiled
1> with
1> [
1> _Elem=std::basic_string<char,std::char_traits<char>,std::allocator<char>>
1> ]
1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\xlocale(2210) : while compiling class template member function 'std::basic_string<_Elem,_Traits,_Ax> std::ctype<std::basic_string<_Elem,_Traits,_Ax>>::do_widen(char) const'
1> with
1> [
1> _Elem=char,
1> _Traits=std::char_traits<char>,
1> _Ax=std::allocator<char>
1> ]
1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\locale(261) : see reference to class template instantiation 'std::ctype<_Elem>' being compiled
1> with
1> [
1> _Elem=std::basic_string<char,std::char_traits<char>,std::allocator<char>>
1> ]
1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\locale(259) : see reference to function template instantiation '_Elem std::toupper<T1>(_Elem,const std::locale &)' being compiled
1> with
1> [
1> _Elem=std::basic_string<char,std::char_traits<char>,std::allocator<char>>,
1> T1=std::basic_string<char,std::char_traits<char>,std::allocator<char>>
1> ]
1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\algorithm(2042) : see reference to function template instantiation 'bool boost::algorithm::is_iequal::operator ()<std::basic_string<_Elem,_Traits,_Ax>,std::basic_string<_Elem,_Traits,_Ax>>(const T1 &,const T2 &) const' being compiled
1> with
1> [
1> _Elem=char,
1> _Traits=std::char_traits<char>,
1> _Ax=std::allocator<char>,
1> T1=std::basic_string<char,std::char_traits<char>,std::allocator<char>>,
1> T2=std::basic_string<char,std::char_traits<char>,std::allocator<char>>
1> ]
1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\algorithm(2070) : see reference to function template instantiation '_OutIt std::_Unique_copy<_InIt,_OutIt,_Pr>(_FwdIt,_FwdIt,_OutIt,_Pr,std::forward_iterator_tag)' being compiled
1> with
1> [
1> _OutIt=std::_Vector_iterator<std::_Vector_val<std::string,std::allocator<std::string>>>,
1> _InIt=std::basic_string<char,std::char_traits<char>,std::allocator<char>> *,
1> _Pr=boost::algorithm::is_iequal,
1> _FwdIt=std::basic_string<char,std::char_traits<char>,std::allocator<char>> *
1> ]
1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\algorithm(2094) : see reference to function template instantiation '_OutIt std::_Unique_copy1<std::basic_string<_Elem,_Traits,_Ax>*,_OutIt,_Pr>(_InIt,_InIt,_OutIt,_Pr,std::tr1::true_type)' being compiled
1> with
1> [
1> _OutIt=std::_Vector_iterator<std::_Vector_val<std::string,std::allocator<std::string>>>,
1> _Elem=char,
1> _Traits=std::char_traits<char>,
1> _Ax=std::allocator<char>,
1> _Pr=boost::algorithm::is_iequal,
1> _InIt=std::basic_string<char,std::char_traits<char>,std::allocator<char>> *
1> ]
1> c:\users\stv04463\documents\visual studio 2010\projects\pgp sandbox\pgp sandbox\main.cpp(64) : see reference to function template instantiation '_OutIt std::unique_copy<std::_Vector_iterator<_Myvec>,std::_Vector_iterator<_Myvec>,boost::algorithm::is_iequal>(_InIt,_InIt,_OutIt,_Pr)' being compiled
1> with
1> [
1> _OutIt=std::_Vector_iterator<std::_Vector_val<std::string,std::allocator<std::string>>>,
1> _Myvec=std::_Vector_val<std::string,std::allocator<std::string>>,
1> _InIt=std::_Vector_iterator<std::_Vector_val<std::string,std::allocator<std::string>>>,
1> _Pr=boost::algorithm::is_iequal
1> ]
1>c:\program files (x86)\microsoft visual studio 10.0\vc\include\xlocale(593): error C2440: 'type cast' : cannot convert from 'std::basic_string<_Elem,_Traits,_Ax>' to 'unsigned char'
1> with
1> [
1> _Elem=char,
1> _Traits=std::char_traits<char>,
1> _Ax=std::allocator<char>
1> ]
1> No user-defined-conversion operator available that can perform this conversion, or the operator cannot be called
1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\xlocale(2229) : see reference to function template instantiation 'char std::_Maklocbyte<std::basic_string<_Elem,_Traits,_Ax>>(std::basic_string<_Elem,_Traits,_Ax>,const std::_Locinfo::_Cvtvec &)' being compiled
1> with
1> [
1> _Elem=char,
1> _Traits=std::char_traits<char>,
1> _Ax=std::allocator<char>
1> ]
1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\xlocale(2225) : while compiling class template member function 'char std::ctype<_Elem>::_Donarrow(_Elem,char) const'
1> with
1> [
1> _Elem=std::basic_string<char,std::char_traits<char>,std::allocator<char>>
1> ]
Am I missing some basic understanding here, or should it not be possible to combine std::unique_copy with boost::is_iequal?
I am aware of the alternatives - I'd like to know why I'm getting this compiler error.
The boost::is_iequal predicate is meant to be used on single characters, not on an entire string like you're doing.
Unfortunately the Boost String Algorithms documentation is not the best, but you can see this specified here: "Defines element comparison predicates", where "element" refers to the string characters.
Internally, boost::is_iequal calls std::toupper on its arguments, and this can only work on characters.
Is this a Boost bug or am I doing something wrong?
#include <map>
#include <boost/pool/pool_alloc.hpp>
int main()
{
typedef const std::string key;
typedef double* (*value)(const int&);
std::map<key, value, std::less<key>> map_with_standard_allocator; // works
std::map<key, value, std::less<key>, boost::fast_pool_allocator<std::pair<const key, value> > > map_with_boost_allocator; // fails
}
the last line fails to compile under MS Visual Studio 2008 with Boost 1.40 and 1.48. It compiles fine under g++ 4.5.3 (Cygwin), though.
The error is:
1>Compiling...
1>main.cpp
1>C:\UniLib1\trunk\External\boost/pool/pool_alloc.hpp(205) : error C2535: 'const std::basic_string<_Elem,_Traits,_Ax> *boost::fast_pool_allocator<T,UserAllocator,Mutex,NextSize>::address(const std::basic_string<_Elem,_Traits,_Ax> &)' : member function already defined or declared
1> with
1> [
1> _Elem=char,
1> _Traits=std::char_traits<char>,
1> _Ax=std::allocator<char>,
1> T=const std::basic_string<char,std::char_traits<char>,std::allocator<char>>,
1> UserAllocator=boost::default_user_allocator_new_delete,
1> Mutex=boost::details::pool::default_mutex,
1> NextSize=32
1> ]
1> C:\UniLib1\trunk\External\boost/pool/pool_alloc.hpp(202) : see declaration of 'boost::fast_pool_allocator<T,UserAllocator,Mutex,NextSize>::address'
1> with
1> [
1> T=const std::basic_string<char,std::char_traits<char>,std::allocator<char>>,
1> UserAllocator=boost::default_user_allocator_new_delete,
1> Mutex=boost::details::pool::default_mutex,
1> NextSize=32
1> ]
1> c:\Program Files\Microsoft Visual Studio 9.0\VC\include\xtree(137) : see reference to class template instantiation 'boost::fast_pool_allocator<T,UserAllocator,Mutex,NextSize>' being compiled
1> with
1> [
1> T=const std::basic_string<char,std::char_traits<char>,std::allocator<char>>,
1> UserAllocator=boost::default_user_allocator_new_delete,
1> Mutex=boost::details::pool::default_mutex,
1> NextSize=32
1> ]
1> c:\Program Files\Microsoft Visual Studio 9.0\VC\include\map(78) : see reference to class template instantiation 'std::_Tree<_Traits>' being compiled
1> with
1> [
1> _Traits=std::_Tmap_traits<key,value ,std::less<key>,boost::fast_pool_allocator<std::pair<key,value >>,false>
1> ]
1> .\main.cpp(9) : see reference to class template instantiation 'std::map<_Kty,_Ty,_Pr,_Alloc>' being compiled
1> with
1> [
1> _Kty=key,
1> _Ty=value,
1> _Pr=std::less<key>,
1> _Alloc=boost::fast_pool_allocator<std::pair<key,value >>
1> ]
This is not a bug in VS2008 (as I mistakenly claimed in an earlier edit to this answer). The C++03 standard requires that the key type for an associative container, like std::map, must be 'assignable' (per Table 69 in 23.1.2 "Associative containers"). And a const std::string is not assignable. Note that the C++11 standard seems to relax this requirement, but the new standard doesn't apply to since VC++ 2008.
It's not clear to me that a compiler is required to diagnose code that tries to use std::map with a non-assignable key, so I don't think one can claim that GCC or VC++ 2010 are accepting this code improperly (I think it falls into the area of undefined code that works as you might expect, even though there's no guarantee it'll work). However it is clear that it's OK for VC++ 2008 to refuse to compile it.
All that said, I think that VC++ 2008's library parameterizing the allocator's address() function on the map's key rather than map's element is still suspect (see the first edit of this answer for details if you're interested), but I don't think there's any real bug there since the std::pair<> used to hold the map element will always be set up such that key part will be at the same address as the whole element.
I need a data structure, and I'm unsure of what to choose. Fundamentally, my need is similar to std::set, except I need to look up according to multiple different comparators over the same data at the same time.
Right now I've decided to go for some kludge- a std::map<float, std::unordered_set<T>> and then a std::unordered_map<T, std::unordered_set<T>*>. This should permit O(log N) lookup for a float and O(1) lookup/removal for a T.
Are there any better data structures to use? This has "hack" written all over it.
As an aside, this code is fairly performance critical, so something fast would be very appreciated.
Edit: I've been poking with boost::multi_index and here's what I've got so far:
boost::multi_index_container<
NodeType,
boost::multi_index::indexed_by<
boost::multi_index::ordered_non_unique<boost::multi_index::identity<NodeType>, decltype(node_comparator)>,
boost::multi_index::hashed_unique<boost::multi_index::identity<NodeType>>
>
> open_set(
boost::make_tuple(node_comparator)
);
where node_comparator is an in_scope lambda. But attempting to compile it results in some glorious errors.
1>d:\backups\code\boost_1_47_0\boost\multi_index\detail\node_type.hpp(56): error C2903: 'node_class' : symbol is neither a class template nor a function template
1> d:\backups\code\boost_1_47_0\boost\mpl\aux_\preprocessed\plain\apply_wrap.hpp(49) : see reference to class template instantiation 'boost::multi_index::detail::index_node_applier::apply<IndexSpecifierIterator,Super>' being compiled
1> with
1> [
1> IndexSpecifierIterator=boost::mpl::v_iter<boost::mpl::vector2<boost::multi_index::ordered_non_unique<boost::multi_index::identity<NodeType>,Wide::Sim::`anonymous-namespace'::<lambda8>>,boost::multi_index::hashed_unique<boost::multi_index::identity<NodeType>>>,0>,
1> Super=boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<NodeType,std::allocator<NodeType>>>
1> ]
1> d:\backups\code\boost_1_47_0\boost\mpl\aux_\preprocessed\plain\bind.hpp(207) : see reference to class template instantiation 'boost::mpl::apply_wrap2<F,T1,T2>' being compiled
1> with
1> [
1> F=boost::multi_index::detail::index_node_applier,
1> T1=boost::mpl::v_iter<boost::mpl::vector2<boost::multi_index::ordered_non_unique<boost::multi_index::identity<NodeType>,Wide::Sim::`anonymous-namespace'::<lambda8>>,boost::multi_index::hashed_unique<boost::multi_index::identity<NodeType>>>,0>,
1> T2=boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<NodeType,std::allocator<NodeType>>>
1> ]
1> d:\backups\code\boost_1_47_0\boost\mpl\aux_\preprocessed\plain\apply_wrap.hpp(49) : see reference to class template instantiation 'boost::mpl::bind2<F,T1,T2>::apply<U1,U2>' being compiled
1> with
1> [
1> F=boost::multi_index::detail::index_node_applier,
1> T1=boost::mpl::_2,
1> T2=boost::mpl::_1,
1> U1=boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<NodeType,std::allocator<NodeType>>>,
1> U2=boost::mpl::v_iter<boost::mpl::vector2<boost::multi_index::ordered_non_unique<boost::multi_index::identity<NodeType>,Wide::Sim::`anonymous-namespace'::<lambda8>>,boost::multi_index::hashed_unique<boost::multi_index::identity<NodeType>>>,0>
1> ]
1> d:\backups\code\boost_1_47_0\boost\mpl\aux_\preprocessed\plain\apply.hpp(63) : see reference to class template instantiation 'boost::mpl::apply_wrap2<F,T1,T2>' being compiled
1> with
1> [
1> F=boost::mpl::bind2<boost::multi_index::detail::index_node_applier,boost::mpl::_2,boost::mpl::_1>,
1> T1=boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<NodeType,std::allocator<NodeType>>>,
1> T2=boost::mpl::v_iter<boost::mpl::vector2<boost::multi_index::ordered_non_unique<boost::multi_index::identity<NodeType>,Wide::Sim::`anonymous-namespace'::<lambda8>>,boost::multi_index::hashed_unique<boost::multi_index::identity<NodeType>>>,0>
1> ]
1> d:\backups\code\boost_1_47_0\boost\mpl\aux_\preprocessed\plain\reverse_iter_fold_impl.hpp(82) : see reference to class template instantiation 'boost::mpl::apply2<F,T1,T2>' being compiled
1> with
1> [
1> F=boost::mpl::bind2<boost::multi_index::detail::index_node_applier,boost::mpl::_2,boost::mpl::_1>,
1> T1=boost::multi_index::detail::hashed_index_node<boost::multi_index::detail::index_node_base<NodeType,std::allocator<NodeType>>>,
1> T2=boost::mpl::v_iter<boost::mpl::vector2<boost::multi_index::ordered_non_unique<boost::multi_index::identity<NodeType>,Wide::Sim::`anonymous-namespace'::<lambda8>>,boost::multi_index::hashed_unique<boost::multi_index::identity<NodeType>>>,0>
1> ]
1> d:\backups\code\boost_1_47_0\boost\mpl\reverse_iter_fold.hpp(43) : see reference to class template instantiation 'boost::mpl::aux::reverse_iter_fold_impl<N,First,Last,State,BackwardOp,ForwardOp>' being compiled
1> with
1> [
1> N=2,
1> First=boost::mpl::v_iter<boost::mpl::vector2<boost::multi_index::ordered_non_unique<boost::multi_index::identity<NodeType>,Wide::Sim::`anonymous-namespace'::<lambda8>>,boost::multi_index::hashed_unique<boost::multi_index::identity<NodeType>>>,0>,
1> Last=boost::mpl::v_iter<boost::mpl::vector2<boost::multi_index::ordered_non_unique<boost::multi_index::identity<NodeType>,Wide::Sim::`anonymous-namespace'::<lambda8>>,boost::multi_index::hashed_unique<boost::multi_index::identity<NodeType>>>,2>,
1> State=boost::multi_index::detail::index_node_base<NodeType,std::allocator<NodeType>>,
1> BackwardOp=boost::mpl::bind2<boost::multi_index::detail::index_node_applier,boost::mpl::_2,boost::mpl::_1>,
1> ForwardOp=boost::mpl::protect<boost::mpl::arg<1>>
1> ]
1> d:\backups\code\boost_1_47_0\boost\multi_index\detail\node_type.hpp(70) : see reference to class template instantiation 'boost::mpl::reverse_iter_fold<Sequence,State,BackwardOp>' being compiled
1> with
1> [
1> Sequence=boost::multi_index::indexed_by<boost::multi_index::ordered_non_unique<boost::multi_index::identity<NodeType>,Wide::Sim::`anonymous-namespace'::<lambda8>>,boost::multi_index::hashed_unique<boost::multi_index::identity<NodeType>>>,
1> State=boost::multi_index::detail::index_node_base<NodeType,std::allocator<NodeType>>,
1> BackwardOp=boost::mpl::bind2<boost::multi_index::detail::index_node_applier,boost::mpl::_2,boost::mpl::_1>
1> ]
1> d:\backups\code\boost_1_47_0\boost\multi_index_container.hpp(75) : see reference to class template instantiation 'boost::multi_index::detail::multi_index_node_type<Value,IndexSpecifierList,Allocator>' being compiled
1> with
1> [
1> Value=NodeType,
1> IndexSpecifierList=boost::multi_index::indexed_by<boost::multi_index::ordered_non_unique<boost::multi_index::identity<NodeType>,Wide::Sim::`anonymous-namespace'::<lambda8>>,boost::multi_index::hashed_unique<boost::multi_index::identity<NodeType>>>,
1> Allocator=std::allocator<NodeType>
1> ]
1> c:\repo\render\render\sim\simcontext.cpp(264) : see reference to class template instantiation 'boost::multi_index::multi_index_container<Value,IndexSpecifierList>' being compiled
1> with
1> [
1> Value=NodeType,
1> IndexSpecifierList=boost::multi_index::indexed_by<boost::multi_index::ordered_non_unique<boost::multi_index::identity<NodeType>,Wide::Sim::`anonymous-namespace'::<lambda8>>,boost::multi_index::hashed_unique<boost::multi_index::identity<NodeType>>>
1> ]
This is just the first; there are many, but I'm well aware of Visual Studio's propensity to let one error cause 9999999 more.
One thing you can try is to use a weak_ptr in your unordered_set, and shared_ptr for your elements. When you destruct the element, a NULL weak_ptr is left behind. You would need some way to garbage collect those NULL weak_ptr entries in your container, but that cost is likely easily amortized. This way, you avoid needing to use a second index at all.
multi_index was the winner. Unfortunately dirkgently posted as comment, not answer, or I'd accept it.