I have made a boost multiindex of my GameObject, and I am trying to loop through and call non const functions on it. And I cannot for the life of me to get boost to stop giving long nasty compiler errors, like saying there is no matching function call and so forth.
Inside of game.hpp, I have this code to declare what my multiindex container looks like:
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include "game_object.hpp"
struct ByPosition {};
struct ByName {};
namespace bmi = boost::multi_index;
typedef boost::multi_index_container<
GameObject,
bmi::indexed_by<
bmi::random_access<
bmi::tag<ByPosition>
>,
bmi::ordered_non_unique<
bmi::tag<ByName>,
bmi::const_mem_fun<GameObject, const std::string&, &GameObject::name>
>
>
> GameObjectCollection;
class Game
{
//... various other code
private:
GameObjectCollection gameObjects_;
}
then inside game_object.hpp:
#pragma once
#include <string>
#include "drawable.hpp"
class GameObject : public Drawable
{
public:
virtual ~GameObject() = default;
virtual void processEvent(const SDL_Event& event) {}
virtual void update(const float deltaTime) {}
const std::string& name() const { return name_; }
void setName(const std::string& name) { name_ = name; }
private:
std::string name_;
};
then inside game.cpp, where the compiler errors are triggered:
void Game::processEvent(const SDL_Event& event)
{
auto& index = gameObjects_.get<ByPosition>();
for (auto it : index)
index.modify(it, [&event](GameObject& object) {
object.processEvent(event);
});
}
void Game::update()
{
auto& index = gameObjects_.get<ByPosition>();
for (const auto& it : index)
index.modify(it, [&](GameObject& object) {
object.update(deltaTime_);
});
}
And with that boost is giving me these long compiler errors:
game.cpp: In member function ‘void Game::processEvent(const SDL_Event&)’:
game.cpp:68:21: error: no matching function for call to ‘boost::multi_index::detail::random_access_index<boost::multi_index::detail::nth_layer<1, GameObject, boost::multi_index::indexed_by<boost::multi_index::random_access<boost::multi_index::tag<ByPosition> >, boost::multi_index::ordered_non_unique<boost::multi_index::tag<ByName>, boost::multi_index::const_mem_fun<GameObject, const std::__cxx11::basic_string<char>&, &GameObject::name> > >, std::allocator<GameObject> >, boost::mpl::v_item<ByPosition, boost::mpl::vector0<mpl_::na>, 0> >::modify(GameObject&, Game::processEvent(const SDL_Event&)::<lambda(GameObject&)>)’
68 | index.modify(it, [&event](GameObject& object) {
| ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
69 | object.processEvent(event);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~
70 | });
| ~~
In file included from game.hpp:6,
from game.cpp:3:
/usr/include/boost/multi_index/random_access_index.hpp:472:8: note: candidate: ‘template<class Modifier> bool boost::multi_index::detail::random_access_index<SuperMeta, TagList>::modify(boost::multi_index::detail::random_access_index<SuperMeta, TagList>::iterator, Modifier) [with Modifier = Modifier; SuperMeta = boost::multi_index::detail::nth_layer<1, GameObject, boost::multi_index::indexed_by<boost::multi_index::random_access<boost::multi_index::tag<ByPosition> >, boost::multi_index::ordered_non_unique<boost::multi_index::tag<ByName>, boost::multi_index::const_mem_fun<GameObject, const std::__cxx11::basic_string<char>&, &GameObject::name> > >, std::allocator<GameObject> >; TagList = boost::mpl::v_item<ByPosition, boost::mpl::vector0<mpl_::na>, 0>]’
472 | bool modify(iterator position,Modifier mod)
| ^~~~~~
/usr/include/boost/multi_index/random_access_index.hpp:472:8: note: template argument deduction/substitution failed:
game.cpp:68:22: note: cannot convert ‘it’ (type ‘GameObject’) to type ‘boost::multi_index::detail::random_access_index<boost::multi_index::detail::nth_layer<1, GameObject, boost::multi_index::indexed_by<boost::multi_index::random_access<boost::multi_index::tag<ByPosition> >, boost::multi_index::ordered_non_unique<boost::multi_index::tag<ByName>, boost::multi_index::const_mem_fun<GameObject, const std::__cxx11::basic_string<char>&, &GameObject::name> > >, std::allocator<GameObject> >, boost::mpl::v_item<ByPosition, boost::mpl::vector0<mpl_::na>, 0> >::iterator’ {aka ‘boost::multi_index::detail::rnd_node_iterator<boost::multi_index::detail::random_access_index_node<boost::multi_index::detail::ordered_index_node<boost::multi_index::detail::null_augment_policy, boost::multi_index::detail::index_node_base<GameObject, std::allocator<GameObject> > > > >’}
68 | index.modify(it, [&event](GameObject& object) {
| ^~
In file included from game.hpp:6,
from game.cpp:3:
/usr/include/boost/multi_index/random_access_index.hpp:493:8: note: candidate: ‘template<class Modifier, class Rollback> bool boost::multi_index::detail::random_access_index<SuperMeta, TagList>::modify(boost::multi_index::detail::random_access_index<SuperMeta, TagList>::iterator, Modifier, Rollback) [with Modifier = Modifier; Rollback = Rollback; SuperMeta = boost::multi_index::detail::nth_layer<1, GameObject, boost::multi_index::indexed_by<boost::multi_index::random_access<boost::multi_index::tag<ByPosition> >, boost::multi_index::ordered_non_unique<boost::multi_index::tag<ByName>, boost::multi_index::const_mem_fun<GameObject, const std::__cxx11::basic_string<char>&, &GameObject::name> > >, std::allocator<GameObject> >; TagList = boost::mpl::v_item<ByPosition, boost::mpl::vector0<mpl_::na>, 0>]’
493 | bool modify(iterator position,Modifier mod,Rollback back_)
| ^~~~~~
/usr/include/boost/multi_index/random_access_index.hpp:493:8: note: template argument deduction/substitution failed:
game.cpp:68:21: note: candidate expects 3 arguments, 2 provided
68 | index.modify(it, [&event](GameObject& object) {
| ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
69 | object.processEvent(event);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~
70 | });
| ~~
game.cpp: In member function ‘void Game::update()’:
game.cpp:78:21: error: no matching function for call to ‘boost::multi_index::detail::random_access_index<boost::multi_index::detail::nth_layer<1, GameObject, boost::multi_index::indexed_by<boost::multi_index::random_access<boost::multi_index::tag<ByPosition> >, boost::multi_index::ordered_non_unique<boost::multi_index::tag<ByName>, boost::multi_index::const_mem_fun<GameObject, const std::__cxx11::basic_string<char>&, &GameObject::name> > >, std::allocator<GameObject> >, boost::mpl::v_item<ByPosition, boost::mpl::vector0<mpl_::na>, 0> >::modify(const GameObject&, Game::update()::<lambda(GameObject&)>)’
78 | index.modify(it, [&](GameObject& object) {
| ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
79 | object.update(deltaTime_);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
80 | });
| ~~
In file included from game.hpp:6,
from game.cpp:3:
/usr/include/boost/multi_index/random_access_index.hpp:472:8: note: candidate: ‘template<class Modifier> bool boost::multi_index::detail::random_access_index<SuperMeta, TagList>::modify(boost::multi_index::detail::random_access_index<SuperMeta, TagList>::iterator, Modifier) [with Modifier = Modifier; SuperMeta = boost::multi_index::detail::nth_layer<1, GameObject, boost::multi_index::indexed_by<boost::multi_index::random_access<boost::multi_index::tag<ByPosition> >, boost::multi_index::ordered_non_unique<boost::multi_index::tag<ByName>, boost::multi_index::const_mem_fun<GameObject, const std::__cxx11::basic_string<char>&, &GameObject::name> > >, std::allocator<GameObject> >; TagList = boost::mpl::v_item<ByPosition, boost::mpl::vector0<mpl_::na>, 0>]’
472 | bool modify(iterator position,Modifier mod)
| ^~~~~~
/usr/include/boost/multi_index/random_access_index.hpp:472:8: note: template argument deduction/substitution failed:
game.cpp:78:22: note: cannot convert ‘it’ (type ‘const GameObject’) to type ‘boost::multi_index::detail::random_access_index<boost::multi_index::detail::nth_layer<1, GameObject, boost::multi_index::indexed_by<boost::multi_index::random_access<boost::multi_index::tag<ByPosition> >, boost::multi_index::ordered_non_unique<boost::multi_index::tag<ByName>, boost::multi_index::const_mem_fun<GameObject, const std::__cxx11::basic_string<char>&, &GameObject::name> > >, std::allocator<GameObject> >, boost::mpl::v_item<ByPosition, boost::mpl::vector0<mpl_::na>, 0> >::iterator’ {aka ‘boost::multi_index::detail::rnd_node_iterator<boost::multi_index::detail::random_access_index_node<boost::multi_index::detail::ordered_index_node<boost::multi_index::detail::null_augment_policy, boost::multi_index::detail::index_node_base<GameObject, std::allocator<GameObject> > > > >’}
78 | index.modify(it, [&](GameObject& object) {
| ^~
In file included from game.hpp:6,
from game.cpp:3:
/usr/include/boost/multi_index/random_access_index.hpp:493:8: note: candidate: ‘template<class Modifier, class Rollback> bool boost::multi_index::detail::random_access_index<SuperMeta, TagList>::modify(boost::multi_index::detail::random_access_index<SuperMeta, TagList>::iterator, Modifier, Rollback) [with Modifier = Modifier; Rollback = Rollback; SuperMeta = boost::multi_index::detail::nth_layer<1, GameObject, boost::multi_index::indexed_by<boost::multi_index::random_access<boost::multi_index::tag<ByPosition> >, boost::multi_index::ordered_non_unique<boost::multi_index::tag<ByName>, boost::multi_index::const_mem_fun<GameObject, const std::__cxx11::basic_string<char>&, &GameObject::name> > >, std::allocator<GameObject> >; TagList = boost::mpl::v_item<ByPosition, boost::mpl::vector0<mpl_::na>, 0>]’
493 | bool modify(iterator position,Modifier mod,Rollback back_)
| ^~~~~~
/usr/include/boost/multi_index/random_access_index.hpp:493:8: note: template argument deduction/substitution failed:
game.cpp:78:21: note: candidate expects 3 arguments, 2 provided
78 | index.modify(it, [&](GameObject& object) {
| ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
79 | object.update(deltaTime_);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
80 | });
| ~~
To fix it I tried for example:
Noticing that it said that 3 arguments were expected instead of 2, so I checked and apparently you might need a rollback function, eventhough some other documentation seems to suggest that is optional, but I tried it anyway, I didn't have anything to do for a rollback so I tried adding empty lambdas, like this, on update for example:
void Game::update()
{
auto& index = gameObjects_.get<ByPosition>();
for (const auto& it : index)
index.modify(it, [&](GameObject& object) {
object.update(deltaTime_);
}, [](GameObject& obj){});
}
but then it still gives me that same complaint in the compiler error messages, where I see this:
/usr/include/boost/multi_index/random_access_index.hpp:472:8: note: template argument deduction/substitution failed:
game.cpp:78:21: note: candidate expects 2 arguments, 3 provided
78 | index.modify(it, [&](GameObject& object) {
| ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
79 | object.update(deltaTime_);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~
80 | }, [](GameObject& object) {});
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
I also tried to fix it all by using functors instead of lambdas, so in my game.hpp, I added:
class ProcessEvent {
public:
ProcessEvent(const SDL_Event& event) : event_(event) {}
void operator()(GameObject& gameObject) { gameObject.processEvent(event_); }
private:
const SDL_Event& event_;
};
class Update {
public:
Update(const float delta) : delta_(delta) {}
void operator()(GameObject& gameObject) { gameObject.update(delta_); }
private:
const float& delta_;
};
and changed the code in game.cpp to:
void Game::processEvent(const SDL_Event& event)
{
auto& index = gameObjects_.get<ByPosition>();
for (auto it : index)
index.modify(it, ProcessEvent(event));
}
void Game::update()
{
auto& index = gameObjects_.get<ByPosition>();
for (const auto& it : index)
index.modify(it, Update(deltaTime_));
}
but that just gives me these compiler error messages:
game.cpp: In member function ‘void Game::processEvent(const SDL_Event&)’:
game.cpp:68:21: error: no matching function for call to ‘boost::multi_index::detail::random_access_index<boost::multi_index::detail::nth_layer<1, GameObject, boost::multi_index::indexed_by<boost::multi_index::random_access<boost::multi_index::tag<ByPosition> >, boost::multi_index::ordered_non_unique<boost::multi_index::tag<ByName>, boost::multi_index::const_mem_fun<GameObject, const std::__cxx11::basic_string<char>&, &GameObject::name> > >, std::allocator<GameObject> >, boost::mpl::v_item<ByPosition, boost::mpl::vector0<mpl_::na>, 0> >::modify(GameObject&, ProcessEvent)’
68 | index.modify(it, ProcessEvent(event));
| ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~
In file included from game.hpp:6,
from game.cpp:3:
/usr/include/boost/multi_index/random_access_index.hpp:472:8: note: candidate: ‘template<class Modifier> bool boost::multi_index::detail::random_access_index<SuperMeta, TagList>::modify(boost::multi_index::detail::random_access_index<SuperMeta, TagList>::iterator, Modifier) [with Modifier = Modifier; SuperMeta = boost::multi_index::detail::nth_layer<1, GameObject, boost::multi_index::indexed_by<boost::multi_index::random_access<boost::multi_index::tag<ByPosition> >, boost::multi_index::ordered_non_unique<boost::multi_index::tag<ByName>, boost::multi_index::const_mem_fun<GameObject, const std::__cxx11::basic_string<char>&, &GameObject::name> > >, std::allocator<GameObject> >; TagList = boost::mpl::v_item<ByPosition, boost::mpl::vector0<mpl_::na>, 0>]’
472 | bool modify(iterator position,Modifier mod)
| ^~~~~~
/usr/include/boost/multi_index/random_access_index.hpp:472:8: note: template argument deduction/substitution failed:
game.cpp:68:22: note: cannot convert ‘it’ (type ‘GameObject’) to type ‘boost::multi_index::detail::random_access_index<boost::multi_index::detail::nth_layer<1, GameObject, boost::multi_index::indexed_by<boost::multi_index::random_access<boost::multi_index::tag<ByPosition> >, boost::multi_index::ordered_non_unique<boost::multi_index::tag<ByName>, boost::multi_index::const_mem_fun<GameObject, const std::__cxx11::basic_string<char>&, &GameObject::name> > >, std::allocator<GameObject> >, boost::mpl::v_item<ByPosition, boost::mpl::vector0<mpl_::na>, 0> >::iterator’ {aka ‘boost::multi_index::detail::rnd_node_iterator<boost::multi_index::detail::random_access_index_node<boost::multi_index::detail::ordered_index_node<boost::multi_index::detail::null_augment_policy, boost::multi_index::detail::index_node_base<GameObject, std::allocator<GameObject> > > > >’}
68 | index.modify(it, ProcessEvent(event));
| ^~
In file included from game.hpp:6,
from game.cpp:3:
/usr/include/boost/multi_index/random_access_index.hpp:493:8: note: candidate: ‘template<class Modifier, class Rollback> bool boost::multi_index::detail::random_access_index<SuperMeta, TagList>::modify(boost::multi_index::detail::random_access_index<SuperMeta, TagList>::iterator, Modifier, Rollback) [with Modifier = Modifier; Rollback = Rollback; SuperMeta = boost::multi_index::detail::nth_layer<1, GameObject, boost::multi_index::indexed_by<boost::multi_index::random_access<boost::multi_index::tag<ByPosition> >, boost::multi_index::ordered_non_unique<boost::multi_index::tag<ByName>, boost::multi_index::const_mem_fun<GameObject, const std::__cxx11::basic_string<char>&, &GameObject::name> > >, std::allocator<GameObject> >; TagList = boost::mpl::v_item<ByPosition, boost::mpl::vector0<mpl_::na>, 0>]’
493 | bool modify(iterator position,Modifier mod,Rollback back_)
| ^~~~~~
/usr/include/boost/multi_index/random_access_index.hpp:493:8: note: template argument deduction/substitution failed:
game.cpp:68:21: note: candidate expects 3 arguments, 2 provided
68 | index.modify(it, ProcessEvent(event));
| ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~
game.cpp: In member function ‘void Game::update()’:
game.cpp:76:21: error: no matching function for call to ‘boost::multi_index::detail::random_access_index<boost::multi_index::detail::nth_layer<1, GameObject, boost::multi_index::indexed_by<boost::multi_index::random_access<boost::multi_index::tag<ByPosition> >, boost::multi_index::ordered_non_unique<boost::multi_index::tag<ByName>, boost::multi_index::const_mem_fun<GameObject, const std::__cxx11::basic_string<char>&, &GameObject::name> > >, std::allocator<GameObject> >, boost::mpl::v_item<ByPosition, boost::mpl::vector0<mpl_::na>, 0> >::modify(const GameObject&, Update)’
76 | index.modify(it, Update(deltaTime_));
| ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
In file included from game.hpp:6,
from game.cpp:3:
/usr/include/boost/multi_index/random_access_index.hpp:472:8: note: candidate: ‘template<class Modifier> bool boost::multi_index::detail::random_access_index<SuperMeta, TagList>::modify(boost::multi_index::detail::random_access_index<SuperMeta, TagList>::iterator, Modifier) [with Modifier = Modifier; SuperMeta = boost::multi_index::detail::nth_layer<1, GameObject, boost::multi_index::indexed_by<boost::multi_index::random_access<boost::multi_index::tag<ByPosition> >, boost::multi_index::ordered_non_unique<boost::multi_index::tag<ByName>, boost::multi_index::const_mem_fun<GameObject, const std::__cxx11::basic_string<char>&, &GameObject::name> > >, std::allocator<GameObject> >; TagList = boost::mpl::v_item<ByPosition, boost::mpl::vector0<mpl_::na>, 0>]’
472 | bool modify(iterator position,Modifier mod)
| ^~~~~~
/usr/include/boost/multi_index/random_access_index.hpp:472:8: note: template argument deduction/substitution failed:
game.cpp:76:22: note: cannot convert ‘it’ (type ‘const GameObject’) to type ‘boost::multi_index::detail::random_access_index<boost::multi_index::detail::nth_layer<1, GameObject, boost::multi_index::indexed_by<boost::multi_index::random_access<boost::multi_index::tag<ByPosition> >, boost::multi_index::ordered_non_unique<boost::multi_index::tag<ByName>, boost::multi_index::const_mem_fun<GameObject, const std::__cxx11::basic_string<char>&, &GameObject::name> > >, std::allocator<GameObject> >, boost::mpl::v_item<ByPosition, boost::mpl::vector0<mpl_::na>, 0> >::iterator’ {aka ‘boost::multi_index::detail::rnd_node_iterator<boost::multi_index::detail::random_access_index_node<boost::multi_index::detail::ordered_index_node<boost::multi_index::detail::null_augment_policy, boost::multi_index::detail::index_node_base<GameObject, std::allocator<GameObject> > > > >’}
76 | index.modify(it, Update(deltaTime_));
| ^~
In file included from game.hpp:6,
from game.cpp:3:
/usr/include/boost/multi_index/random_access_index.hpp:493:8: note: candidate: ‘template<class Modifier, class Rollback> bool boost::multi_index::detail::random_access_index<SuperMeta, TagList>::modify(boost::multi_index::detail::random_access_index<SuperMeta, TagList>::iterator, Modifier, Rollback) [with Modifier = Modifier; Rollback = Rollback; SuperMeta = boost::multi_index::detail::nth_layer<1, GameObject, boost::multi_index::indexed_by<boost::multi_index::random_access<boost::multi_index::tag<ByPosition> >, boost::multi_index::ordered_non_unique<boost::multi_index::tag<ByName>, boost::multi_index::const_mem_fun<GameObject, const std::__cxx11::basic_string<char>&, &GameObject::name> > >, std::allocator<GameObject> >; TagList = boost::mpl::v_item<ByPosition, boost::mpl::vector0<mpl_::na>, 0>]’
493 | bool modify(iterator position,Modifier mod,Rollback back_)
| ^~~~~~
/usr/include/boost/multi_index/random_access_index.hpp:493:8: note: template argument deduction/substitution failed:
game.cpp:76:21: note: candidate expects 3 arguments, 2 provided
76 | index.modify(it, Update(deltaTime_));
| ~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~
I have been struggling trying to figure this all out for hours now.
Hopefully someone here can help me out with this.
Thank you.
You need to pass an iterator. it
is now a copy of the element. Instead, use e.g.:
for (auto it = index.begin(); it != index.end(); ++it)
index.modify(it, [&event](GameObject& object) { object.processEvent(event); });
See it Live On Coliru
#include <boost/multi_index/mem_fun.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <boost/multi_index_container.hpp>
#include <string>
//#include "drawable.hpp"
#include <SDL2/SDL.h>
class Drawable {
public:
virtual ~Drawable() = default;
virtual void update(float const deltaTime) = 0;
};
// end stub
class GameObject : public Drawable {
public:
virtual ~GameObject() = default;
virtual void processEvent(SDL_Event const& /*event*/) {}
virtual void update(float const /*deltaTime*/) {}
std::string const& name() const { return name_; }
void setName(std::string const& name) { name_ = name; }
private:
std::string name_;
};
namespace bmi = boost::multi_index;
typedef boost::multi_index_container<
GameObject,
bmi::indexed_by<
bmi::random_access<bmi::tag<struct ByPosition>>,
bmi::ordered_non_unique<bmi::tag<struct ByName>,
bmi::const_mem_fun<GameObject, std::string const&, &GameObject::name>>>>
GameObjectCollection;
class Game {
//... various other code
public:
void processEvent(SDL_Event const& event) {
auto& index = gameObjects_.get<ByPosition>();
for (auto it = index.begin(); it != index.end(); ++it)
index.modify(it, [&event](GameObject& object) { object.processEvent(event); });
}
void update() {
auto& index = gameObjects_.get<ByPosition>();
for (auto it = index.begin(); it != index.end(); ++it)
index.modify(it, [&](GameObject& object) { object.update(deltaTime_); });
}
private:
static constexpr float deltaTime_ = 0.1f;
GameObjectCollection gameObjects_;
};
int main() {
Game game;
// Example usage
SDL_Event event;
// Initialize SDL and create an event loop here...
while (true) {
// Poll events and call game.processEvent(event);
game.processEvent(event);
// Update game state
game.update();
// Render the game...
}
}