Casting std::shared_ptr<Derived<T>> to std::shared_ptr<Base> - c++

I have a base class and a templated derived class as below
class ComponentArray_Base
{
public:
virtual ~ComponentArray_Base() = default;
virtual void EntityDestroyed(Entity entity) = 0;
};
template <typename cType>
class ComponentArray : public ComponentArray_Base
{
//Derived class implementation...
}
and later in the code, outside of the two classes I attempt to add the derived class to an unordered map with
mComponentArrays.insert({ TypeName, std::make_shared<ComponentArray<cType>> });
which gives me the error
C:\Users\davis\source\repos\ECS\ECS\Component.h(91,1): error C2664: 'void std::_Hash<std::_Umap_traits<_Kty,_Ty,std::_Uhash_compare<_Kty,_Hasher,_Keyeq>,_Alloc,false>>::insert(std::initializer_list<std::pair<const char *const ,std::shared_ptr<ComponentArray_Base>>>)': cannot convert argument 1 from 'initializer list' to 'std::initializer_list<_Ty>'
1> with
1> [
1> _Kty=const char *,
1> _Ty=std::shared_ptr<ComponentArray_Base>,
1> _Hasher=std::hash<const char *>,
1> _Keyeq=std::equal_to<const char *>,
1> _Alloc=std::allocator<std::pair<const char *const ,std::shared_ptr<ComponentArray_Base>>>
1> ]
1> and
1> [
1> _Ty=std::pair<const char *const ,std::shared_ptr<ComponentArray_Base>>
1> ]
I do not seem to be having this problem when using a raw pointer and cannot figure out what the problem is as the hash function should be defined for const char*
Using std::static_ptr_cast as below also gives an error,
mComponentArrays.insert({ TypeName, std::static_pointer_cast<ComponentArray_Base>(std::make_shared<ComponentArray<cType>>) });
gives me
'std::static_pointer_cast': none of the 2 overloads could convert all the argument types
1>C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.28.29910\include\memory(2095,29): message : could be 'std::shared_ptr<ComponentArray_Base> std::static_pointer_cast<ComponentArray_Base,ComponentArray<cType>>(std::shared_ptr<ComponentArray<cType>> &&) noexcept'
1> with
1> [
1> cType=Renderable
1> ]

I successfully compile below example. Did I miss sth?
#include <unordered_map>
#include <string>
#include <memory>
class ComponentArray_Base
{
public:
virtual ~ComponentArray_Base() = default;
virtual void EntityDestroyed(int entity) = 0;
};
template <typename cType>
class ComponentArray : public ComponentArray_Base
{
void EntityDestroyed(int entity) override
{
return;
}
//Derived class implementation...
};
std::unordered_map<std::string, std::shared_ptr<ComponentArray_Base>> mComponentArrays;
int main()
{
mComponentArrays.insert({ "Sth", std::make_shared<ComponentArray<int>>() });
return 0;
}

Related

Call member method of a variadic class template with a member field

I learned a bit about variadic templates and searched over the Internet for some samples and now trying to write some tricky code to call member a method of a variadic class template with one of its fields. I can't understand why it doesn't work. Please, help.
Here is sample classes:
class BarBase
{
public:
BarBase() = default;
virtual void call() = 0;
};
template<typename O, typename M, typename... A>
class Bar
: public BarBase
{
public:
Bar(O* o, M m, A&&... a)
: BarBase()
, m_o(o), m_m(m), m_a(std::forward<A>(a)...)
{ }
void call() override final
{
callInnerWithArgsInside();
}
private:
void callInnerWithArgsInside()
{
(m_o->*m_m)(m_a); // Some errors happends here
}
O* m_o;
M m_m;
std::tuple<typename std::remove_reference<A>::type...> m_a;
};
template<typename O, typename M, typename... A>
BarBase* crateBar(O* o, M m, A&&... a)
{
return new Bar<O, M, A...>(o, m, std::forward<A>(a)...);
}
And call from main:
struct Foo
{
void foo(int ii, float ff, std::string ss)
{
std::cout << "called" << std::endl;
}
};
int main()
{
Foo f;
int i = 10;
float ff = 20.2f;
std::string s = "Hello";
BarBase* bar = crateBar(&f, &Foo::foo, i, ff, s);
bar->call();
}
Errors:
main.cpp
1>d:\drafts_tests\main.cpp(203): error C2198: 'void (__thiscall Foo::* )(int,float,std::string)' : too few arguments for call
1> d:\drafts_tests\main.cpp(202) : while compiling class template member function 'void Bar::callInnerWithArgsInside(void)'
1> with
1> [
1> O=Foo
1> , M=void (__thiscall Foo::* )(int,float,std::string)
1> ]
1> d:\drafts_tests\main.cpp(197) : see reference to function template instantiation 'void Bar::callInnerWithArgsInside(void)' being compiled
1> with
1> [
1> O=Foo
1> , M=void (__thiscall Foo::* )(int,float,std::string)
1> ]
1> d:\drafts_tests\main.cpp(214) : see reference to class template instantiation 'Bar' being compiled
1> with
1> [
1> O=Foo
1> , M=void (__thiscall Foo::* )(int,float,std::string)
1> ]
1> d:\drafts_tests\main.cpp(225) : see reference to function template instantiation 'BarBase *crateBar(O *,M,int &,float &,std::string &)' being compiled
1> with
1> [
1> O=Foo
1> , M=void (__thiscall Foo::* )(int,float,std::string)
1> ]
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
you are passing a tuple to the function, rather than the individual type arguments. The following will pass the required type args to the call:
template<std::size_t... I>
void callInnerWithArgsInside2(std::index_sequence<I...>)
{
(m_o->*m_m)(std::get<I>(m_a)...);
}
void callInnerWithArgsInside()
{
return callInnerWithArgsInside2( std::make_index_sequence<sizeof...(A)>());
}
live demo
EDIT1: C++11 version
I have implemented a C++11 version, see updated live demo

Cannot instantiate abstract class using c++11

Why can't I use an abstract class like an interface at runtime.
I get the output:
1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\xmemory0(615): error C2259: 'Creature' : cannot instantiate abstract class
1> due to following members:
1> 'std::string Creature::Move(std::vector<std::string,std::allocator<_Ty>> &)' : is abstract
1> with
1> [
1> _Ty=std::string
1> ]
1> visual studio 2013\projects\cpp_demo\cpp_demo\creature.h(9) : see declaration of 'Creature::Move'
1> c:\program files (x86)\microsoft visual studio 12.0\vc\include\xmemory0(614) : while compiling class template member function 'void std::allocator<_Ty>::construct(_Ty *,const _Ty &)'
1> with
1> [
1> _Ty=Creature
1> ]
1> c:\program files (x86)\microsoft visual studio 12.0\vc\include\xmemory0(752) : see reference to function template instantiation 'void std::allocator<_Ty>::construct(_Ty *,const _Ty &)' being compiled
1> with
1> [
1> _Ty=Creature
1> ]
1> c:\program files (x86)\microsoft visual studio 12.0\vc\include\type_traits(580) : see reference to class template instantiation 'std::allocator<_Ty>' being compiled
1> with
1> [
1> _Ty=Creature
1> ]
1> c:\program files (x86)\microsoft visual studio 12.0\vc\include\vector(650) : see reference to class template instantiation 'std::is_empty<_Alloc>' being compiled
1> with
1> [
1> _Alloc=std::allocator<Creature>
1> ]
1> visual studio 2013\projects\cpp_demo\cpp_demo\main.cpp(7) : see reference to class template instantiation 'std::vector<Creature,std::allocator<_Ty>>' being compiled
1> with
1> [
1> _Ty=Creature
1> ]
My code:
int main()
{
unique_ptr<vector<Creature>> pCreatures(new vector<Creature>);
unique_ptr<Creature> pHuman(new Human());
pCreatures->push_back(*pHuman);
}
#include "stdafx.h"
#include "Creature.h"
class Human : public Creature
{
public:
virtual string Move(vector<string> &log);
};
#include "stdafx.h"
#include "IMove.h"
class Creature : public IMove
{
public:
virtual string Move(vector<string> &log) = 0;
virtual string GetState(vector<string> &log);
};
Please help.
You CAN use abstract class in vector or unique_ptr, e.g.
#include <vector>
#include <memory>
using namespace std;
class Interface {
public:
virtual ~Interface() = 0;
};
Interface::~Interface() {}
class Implementation : public Interface {
};
int main(int argc, char** argv) {
unique_ptr<Interface> p(new Implementation);
vector<unique_ptr<Interface>> v;
v.emplace_back(new Implementation);
vector<Interface> vi;
// This leads to compile error: vi.emplace_back();
}
Moreover, you CAN use vector<Interface> as long as you don't call any methods that potentially calls new Interface. For example, if you just declare a variable vector<Interface> v; it compiles, but if you push_back or emplace_back or resize, then it will have compile error because they will call new Interface.
The above code is tested under gcc-4.6.3.
You can use, but instead of using:
unique_ptr<vector<Creature>> pCreatures(new vector<Creature>);
use
vector<unique_ptr<Creature>> pCreatures;
so you will have a vectors of Creatures pointers, managed by unique_ptr.
There are, at least, two ways to use this vector:
Creating the objects directly into the vector:
pCreatures.emplace_back(new Human());
Moving an unique_ptr to it:
unique_ptr pHuman(new Human());
pCreatures.push_back(move(pHuman));
Below is a compact usage:
int main()
{
vector<unique_ptr<Creature>> pCreatures;
pCreatures.emplace_back(new Human());
unique_ptr<Creature> pHuman(new Human());
pCreatures.push_back(move(pHuman));
// example of usage
pCreatures[0]->Move();
}

access to different data via c++ templates

I'm trying to make a manager, which provides access via templates to containers that store different types of data.
First of all, i made base manager class for storing different type of data
template <typename T>
class BaseMapManager{
public:
T add(T element, std::string name);
T remove(T element);
T remove(std::string name);
T remove(unsigned int id);
T get(std::string name);
T get(unsigned int id);
BaseMapManager() { id = 0; };
~BaseMapManager() { nameMap.clear(); idMap.clear(); };
protected:
std::map<std::string, T> nameMap;
std::map<unsigned int, T> idMap;
//each element of type T gets new unique id
unsigned int id;
//hide it
BaseMapManager(const BaseMapManager&) {};
BaseMapManager& operator=(const BaseMapManager&) {};
};
Then i made my concrete manager, which had to store 3 types of baseMapManagers:
class ResourceManager{
public:
//creates singleton
static ResourceManager* init(){
static ResourceManager singleton;
return &singleton;
}
template <typename T>
void load_resource(std::string path, std::string name){
get_map<std::shared_ptr<T>>().add(std::shared_ptr<T>(new T(path, name), name);
}
template <typename T>
std::shared_ptr<T> get_resource(std::string name){
get_map<T>().get(name);
}
template <typename T>
std::shared_ptr<T> get_resource(unsigned int id){
get_map<T>().get(id);
}
private:
BaseMapManager<std::shared_ptr<AnimationResource> > animationMap;
BaseMapManager<std::shared_ptr<ImageResource> > imageMap;
BaseMapManager<std::shared_ptr<FontResource> > fontMap;
template <typename T>
BaseMapManager<T>& get_map(){
if (std::is_same<T, std::shared_ptr<AnimationResource> >() == true) return animationMap;
if (std::is_same<T, std::shared_ptr<ImageResource> >() == true) return imageMap;
if (std::is_same<T, std::shared_ptr<FontResource> >() == true) return fontMap;
};
};
and now i got this:
1>------ Build started: Project: BOSS, Configuration: Debug Win32 ------
1> main.cpp
1>d:\programming\github projects\boss\boss\new\resourcemanager\resourcemanager.h(43):
error C2440: 'return' : cannot convert from 'BaseMapManager<T>' to 'BaseMapManager<T> &'
1> with
1> [
1> T=std::shared_ptr<ImageResource>
1> ]
1> and
1> [
1> T=std::shared_ptr<AnimationResource>
1> ]
1> d:\programming\github projects\boss\boss\new\resourcemanager\resourcemanager.h(21) : see reference to function template instantiation 'BaseMapManager<T> &ResourceManager::get_map<std::shared_ptr<_Ty>>(void)' being compiled
1> with
1> [
1> T=std::shared_ptr<AnimationResource>,
1> _Ty=AnimationResource
1> ]
1> d:\programming\github projects\boss\boss\new\main.cpp(17) : see reference to function template instantiation 'void ResourceManager::load_resource<AnimationResource>(std::string,std::string)' being compiled
1>d:\programming\github projects\boss\boss\new\resourcemanager\resourcemanager.h(44): error C2440: 'return' : cannot convert from 'BaseMapManager<T>' to 'BaseMapManager<T> &'
1> with
1> [
1> T=std::shared_ptr<FontResource>
1> ]
1> and
1> [
1> T=std::shared_ptr<AnimationResource>
1> ]
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0 skipped ==========
The goal is - providing access to different types on data using template functions like
manager->get_resource<AnimationResource>(itsName) //get it or
manager->load_resource<FontResource>(itsPath, itsName) //add it
Is there a better way to handle this maybe? Thanks!
edit
The source of your problem seams to be the is_same function not resolving correctly at compile time.
/edit
You can always have template functions that only work with the specified types.
For example:
template<>
BaseMapManager<AnimationResource> get_map<AnimationResource>()
{
return animationMap;
}
template<>
BaseMapManager<ImageResource> get_map<ImageResource>()
{
return imageMap;
}
template<>
BaseMapManager<FontResource> get_map<FontResource>()
{
return fontMap;
}

Storing containers in a boost::variant

The last line here:
typedef boost::variant<std::vector<int>, std::vector<float>> C;
class A: public boost::static_visitor<>
{
public:
void operator()(const std::vector<int>& value) const
{
}
void operator()(const std::vector<float>& value) const
{
}
};
C container(std::vector<float>());
boost::apply_visitor(A(), container );
Is giving me the error:
c:\boost_1_49_0\boost\variant\detail\apply_visitor_unary.hpp(60): error C2228: left of '.apply_visitor' must have class/struct/union
1> type is 'boost::variant<T0_,T1> (__cdecl &)'
1> with
1> [
1> T0_=std::vector<int>,
1> T1=std::vector<float>
1> ]
1> c:\visual studio 2010\projects\db\xxx\main.cpp(255) : see reference to function template instantiation 'void boost::apply_visitor<A,C(std::vector<_Ty> (__cdecl *)(void))>(Visitor &,Visitable (__cdecl &))' being compiled
1> with
1> [
1> _Ty=float,
1> Visitor=A,
1> Visitable=C (std::vector<float> (__cdecl *)(void))
What is the problem here? Is it sensible in you opinion to have a container type C which such a definition?
I am using the following type throughout my code:
typedef boost::variant<int, float, ...> Type;
Do you think it would be wiser to use this container definition instead:
typedef std::vector<Type> C; // mixed container
Why?
Your problem is that this
C container(std::vector<float>());
is a function declaration (that’s the most vexing parse) (a function container which takes a function returning std::vector<float> as its sole argument, and returns C). Easy fix: extra parentheses:
C container((std::vector<float>()));
The fact that you’re using containers in the variant is irrelevant to the problem. The same would have happened with boost::variant<int, float>.

Using boost::multi_index_container

I've been attempting to use boost::multi_index_container to solve a problem I'm having. However, the multi_index_container fails to compile even the declaration. The error is deep in an MPL function and I have little idea where the fault lies.
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)
);
In this case, node_comparator is a lambda, and NodeType itself already has a std::hash specialization. Here's the text of the error:
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> ]
Any suggestions as to the cause?
Edit: There's pretty much no context to be had. But here's an SSCCE for those of you who can't live without one:
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
struct NodeType {
int x, y, z;
float g_score;
NodeType(int ax, int ay, int az) {
x = ax;
y = ay;
z = az;
}
NodeType() {}
bool operator==(const NodeType& other) const {
return x == other.x && y == other.y && z == other.z;
}
};
template<> struct std::hash<NodeType> : public std::unary_function<const NodeType&, std::size_t> {
std::size_t operator()(const NodeType& node) const {
return std::hash<int>()(node.x * 100000 + node.y * 1000 + node.z);
}
};
template<> struct boost::hash<NodeType> : public std::unary_function<const NodeType&, std::size_t> {
std::size_t operator()(const NodeType& node) const {
return std::hash<int>()(node.x * 100000 + node.y * 1000 + node.z);
}
};
int main() {
auto h = [&](NodeType x) {
return 5.0f; // details irrelevant
};
auto node_comparator = [&](NodeType lhs, NodeType rhs) {
return lhs.g_score + h(lhs) < rhs.g_score + h(rhs);
};
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)
);
}
After your SSCCE post: maybe you forgot to add the following?
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/identity.hpp>
Other than that, I can't compile your code here because my environment is pre-C++11, but I did manage to make it work adding the missing includes and replacing lambdas with regular named functions. Note I had to change the construction args of open_setas explained in another answer:
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/identity.hpp>
struct NodeType {
int x, y, z;
float g_score;
NodeType(int ax, int ay, int az) {
x = ax;
y = ay;
z = az;
}
NodeType() {}
bool operator==(const NodeType& other) const {
return x == other.x && y == other.y && z == other.z;
}
};
template<> struct boost::hash<NodeType> : public std::unary_function<const NodeType&, std::size_t> {
std::size_t operator()(const NodeType& node) const {
return boost::hash<int>()(node.x * 100000 + node.y * 1000 + node.z);
}
};
double h(NodeType x) {
return 5.0f;
}
bool node_comparator(NodeType lhs, NodeType rhs) {
return lhs.g_score + h(lhs) < rhs.g_score + h(rhs);
}
int main() {
typedef boost::multi_index_container<
NodeType,
boost::multi_index::indexed_by<
boost::multi_index::ordered_non_unique<boost::multi_index::identity<NodeType>, bool (*)(NodeType,NodeType)>,
boost::multi_index::hashed_unique<boost::multi_index::identity<NodeType>>
>
> open_set_t;
open_set_t open_set(
boost::make_tuple(
boost::make_tuple(
boost::multi_index::identity<NodeType>(),
&node_comparator
),
open_set_t::nth_index<1>::type::ctor_args()
)
);
}
Additional note: your lambda functions are taking NodeTypes by value, I guess they'd be more efficient if they accepted their arguments as const NodeType&s.
Trying to guess what the problem is with so little context makes for a fun pastime but reduces your chances that you get a useful answer. Ideally you should be providing a complete testcase (i.e. a short compilable program) showing the issue. Anyway, a shot in the dark: you say that NodeTypehas a dedicated std::hash specialization, but Boost.MultiIndex uses boost::hash as its default hash generator. Try looking there.
Another shot in the dark (i think this is it): as decltype(node_comparator) is not default constructible you have to provide an initialization value (node_comparator itself) during open_setconstruction. This is what seemingly you're trying to do, but incorrectly: the right way is as follows (modulo potential typos, more details here):
typedef boost::multi_index_container<
NodeType,
...
> open_set_t;
open_set_t open_set(
boost::make_tuple(
boost::make_tuple(
boost::multi_index::identity<NodeType>(),
node_comparator
),
open_set_t::nth_index<1>::type::ctor_args()
)
);
Given the verbosity imposed by the use of a lambda expression here, I think you're better off by writing a used-defined, default constructible comparator class instead of node_comparator.