-1

I am working through the SFML Game Development book, but I have encountered a problem with std::bind. I searched for a solution, and it seems others have had a similar problem. However, I still was unable to find a solution to this particular problem. Here is my code:

DataTables.hpp

#ifndef DATA_TABLES_HPP
#define DATA_TABLES_HPP

#include <functional>
#include <vector>

struct PickupData {
    std::function<void(Aircraft&)> action;
}

std::vector<PickupData> initializePickupData();

#endif

DataTables.cpp

using namespace std::placeholders;

std::vector<PickupData> initializePickupData() {
    std::vector<PickupData> data(static_cast<int>(Pickup::Type::TypeCount));

    data[static_cast<int>(Pickup::Type::HealthRefill)].action = std::bind(&Aircraft::repair, _1, 25);

    data[static_cast<int>(Pickup::Type::MissileRefill)].action = std::bind(&Aircraft::collectMissiles, _1, 3);

    data[static_cast<int>(Pickup::Type::FireSpread)].action = std::bind(&Aircraft::increaseSpread, _1);

    data[static_cast<int>(Pickup::Type::FireRate)].action = std::bind(&Aircraft::increaseFireRate, _1);

    return data;
}

Entity.hpp

#ifndef ENTITY_HPP
#define ENTITY_HPP

class Entity {
    public:
        explicit Entity(int hitpoints);

        void repair(int points);

    protected:
        int hitpoints;
};

#endif

Entity.cpp

#include "Entity.hpp"

#include <cassert>

Entity::Entity(int hitpoints)
    : hitpoints(hitpoints)
{}

void Entity::repair(int points) {
    assert(points > 0);

    hitpoints += points;
}

Aircraft.hpp

#ifndef AIRCRAFT_HPP
#define AIRCRAFT_HPP

class Aircraft : public Entity {
    public:
        Aircraft();

        void increaseFireRate();
        void increaseSpread();
        void collectMissiles(unsigned int count);

    private:
        int missileAmmo;
        int fireRateLevel;
        int spreadLevel;
}

#endif

Aircraft.cpp

#include "Aircraft.hpp"

Aircraft::Aircraft()
    : Entity(100)
    , missileAmmo(2)
    , fireRateLevel(1)
    , spreadLevel(1)
{}

void Aircraft::collectMissiles(unsigned int count) {
    missileAmmo += count;
}

void Aircraft::increaseSpread() {
    if (spreadLevel < 3)
        ++spreadLevel;
}

void Aircraft::increaseFireRate() {
    if (fireRateLevel < 10)
        ++fireRateLevel;
}

Pickup.hpp

#ifndef PICKUP_HPP
#define PICKUP_HPP

#include "Entity.hpp"
#include "Aircraft.hpp"

class Pickup : public Entity {
    public:
        enum class Type {
            HealthRefil,
            MissileRefill,
            FireSpread,
            FireRate,
            TypeCount
        }

        explicit Pickup(Type type);

        void apply(Aircraft& player) const;

    private:
        Type type;
}

#endif

Pickup.cpp

#include "Pickup.hpp"

#include "DataTables.hpp"

namespace {
    const std::vector<PickupData> Table = initializePickupData();
}

Pickup::Pickup(Type type)
    : Entity(1)
    , type(type)
{}

void Pickup::apply(Aircraft& player) const {
    Table[static_cast<int>(type)].action(player);
}

And here is the error:

1>c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(1241): error C2100: illegal indirection
1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(1149) : see reference to function template instantiation '_Rx std::_Pmf_wrap<void (__thiscall Entity::* )(int),_Rx,Entity,int>::operator ()<Aircraft>(_Wrapper &,int) const' being compiled
1>          with
1>          [
1>              _Rx=void
1>  ,            _Wrapper=Aircraft
1>          ]
1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(1149) : see reference to function template instantiation '_Rx std::_Pmf_wrap<void (__thiscall Entity::* )(int),_Rx,Entity,int>::operator ()<Aircraft>(_Wrapper &,int) const' being compiled
1>          with
1>          [
1>              _Rx=void
1>  ,            _Wrapper=Aircraft
1>          ]
1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(1137) : see reference to function template instantiation 'void std::_Bind<true,void,std::_Pmf_wrap<void (__thiscall Entity::* )(int),void,Entity,int>,std::_Ph<1> &,int>::_Do_call<Aircraft,0,1>(std::tuple<Aircraft &>,std::_Arg_idx<0,1>)' being compiled
1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(1137) : see reference to function template instantiation 'void std::_Bind<true,void,std::_Pmf_wrap<void (__thiscall Entity::* )(int),void,Entity,int>,std::_Ph<1> &,int>::_Do_call<Aircraft,0,1>(std::tuple<Aircraft &>,std::_Arg_idx<0,1>)' being compiled
1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\xrefwrap(283) : see reference to function template instantiation 'void std::_Bind<true,void,std::_Pmf_wrap<void (__thiscall Entity::* )(int),void,Entity,int>,std::_Ph<1> &,int>::operator ()<Aircraft&>(Aircraft &)' being compiled
1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\xrefwrap(283) : see reference to function template instantiation 'void std::_Bind<true,void,std::_Pmf_wrap<void (__thiscall Entity::* )(int),void,Entity,int>,std::_Ph<1> &,int>::operator ()<Aircraft&>(Aircraft &)' being compiled
1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(228) : see reference to function template instantiation '_Ret std::_Callable_obj<std::_Bind<true,_Ret,std::_Pmf_wrap<void (__thiscall Entity::* )(int),void,Entity,int>,std::_Ph<1> &,int>,false>::_ApplyX<_Rx,Aircraft&>(Aircraft &)' being compiled
1>          with
1>          [
1>              _Ret=void
1>  ,            _Rx=void
1>          ]
1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(228) : see reference to function template instantiation '_Ret std::_Callable_obj<std::_Bind<true,_Ret,std::_Pmf_wrap<void (__thiscall Entity::* )(int),void,Entity,int>,std::_Ph<1> &,int>,false>::_ApplyX<_Rx,Aircraft&>(Aircraft &)' being compiled
1>          with
1>          [
1>              _Ret=void
1>  ,            _Rx=void
1>          ]
1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(226) : while compiling class template member function 'void std::_Func_impl<_MyWrapper,_Alloc,_Ret,Aircraft &>::_Do_call(Aircraft &)'
1>          with
1>          [
1>              _Alloc=std::allocator<std::_Func_class<void,Aircraft &>>
1>  ,            _Ret=void
1>          ]
1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(495) : see reference to class template instantiation 'std::_Func_impl<_MyWrapper,_Alloc,_Ret,Aircraft &>' being compiled
1>          with
1>          [
1>              _Alloc=std::allocator<std::_Func_class<void,Aircraft &>>
1>  ,            _Ret=void
1>          ]
1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(396) : see reference to function template instantiation 'void std::_Func_class<_Ret,Aircraft &>::_Do_alloc<_Myimpl,_Ty,_Alloc>(_Fty &&,_Alloc)' being compiled
1>          with
1>          [
1>              _Ret=void
1>  ,            _Ty=std::_Bind<true,void,std::_Pmf_wrap<void (__thiscall Entity::* )(int),void,Entity,int>,std::_Ph<1> &,int>
1>  ,            _Alloc=std::allocator<std::_Func_class<void,Aircraft &>>
1>  ,            _Fty=std::_Bind<true,void,std::_Pmf_wrap<void (__thiscall Entity::* )(int),void,Entity,int>,std::_Ph<1> &,int>
1>          ]
1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(396) : see reference to function template instantiation 'void std::_Func_class<_Ret,Aircraft &>::_Do_alloc<_Myimpl,_Ty,_Alloc>(_Fty &&,_Alloc)' being compiled
1>          with
1>          [
1>              _Ret=void
1>  ,            _Ty=std::_Bind<true,void,std::_Pmf_wrap<void (__thiscall Entity::* )(int),void,Entity,int>,std::_Ph<1> &,int>
1>  ,            _Alloc=std::allocator<std::_Func_class<void,Aircraft &>>
1>  ,            _Fty=std::_Bind<true,void,std::_Pmf_wrap<void (__thiscall Entity::* )(int),void,Entity,int>,std::_Ph<1> &,int>
1>          ]
1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(385) : see reference to function template instantiation 'void std::_Func_class<_Ret,Aircraft &>::_Reset_alloc<_Ty,std::allocator<std::_Func_class<_Ret,Aircraft &>>>(_Fty &&,_Alloc)' being compiled
1>          with
1>          [
1>              _Ret=void
1>  ,            _Ty=std::_Bind<true,void,std::_Pmf_wrap<void (__thiscall Entity::* )(int),void,Entity,int>,std::_Ph<1> &,int>
1>  ,            _Fty=std::_Bind<true,void,std::_Pmf_wrap<void (__thiscall Entity::* )(int),void,Entity,int>,std::_Ph<1> &,int>
1>  ,            _Alloc=std::allocator<std::_Func_class<void,Aircraft &>>
1>          ]
1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(385) : see reference to function template instantiation 'void std::_Func_class<_Ret,Aircraft &>::_Reset_alloc<_Ty,std::allocator<std::_Func_class<_Ret,Aircraft &>>>(_Fty &&,_Alloc)' being compiled
1>          with
1>          [
1>              _Ret=void
1>  ,            _Ty=std::_Bind<true,void,std::_Pmf_wrap<void (__thiscall Entity::* )(int),void,Entity,int>,std::_Ph<1> &,int>
1>  ,            _Fty=std::_Bind<true,void,std::_Pmf_wrap<void (__thiscall Entity::* )(int),void,Entity,int>,std::_Ph<1> &,int>
1>  ,            _Alloc=std::allocator<std::_Func_class<void,Aircraft &>>
1>          ]
1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(688) : see reference to function template instantiation 'void std::_Func_class<_Ret,Aircraft &>::_Reset<_Ty>(_Fty &&)' being compiled
1>          with
1>          [
1>              _Ret=void
1>  ,            _Ty=std::_Bind<true,void,std::_Pmf_wrap<void (__thiscall Entity::* )(int),void,Entity,int>,std::_Ph<1> &,int>
1>  ,            _Fty=std::_Bind<true,void,std::_Pmf_wrap<void (__thiscall Entity::* )(int),void,Entity,int>,std::_Ph<1> &,int>
1>          ]
1>          c:\program files (x86)\microsoft visual studio 12.0\vc\include\functional(688) : see reference to function template instantiation 'void std::_Func_class<_Ret,Aircraft &>::_Reset<_Ty>(_Fty &&)' being compiled
1>          with
1>          [
1>              _Ret=void
1>  ,            _Ty=std::_Bind<true,void,std::_Pmf_wrap<void (__thiscall Entity::* )(int),void,Entity,int>,std::_Ph<1> &,int>
1>  ,            _Fty=std::_Bind<true,void,std::_Pmf_wrap<void (__thiscall Entity::* )(int),void,Entity,int>,std::_Ph<1> &,int>
1>          ]
1>          c:\users\alec\desktop\c++ code\sfmlproject\sfmlproject\datatables.cpp(78) : see reference to function template instantiation 'std::function<void (Aircraft &)> &std::function<void (Aircraft &)>::operator =<std::_Bind<true,void,std::_Pmf_wrap<void (__thiscall Entity::* )(int),void,Entity,int>,std::_Ph<1> &,int>>(_Fx &&)' being compiled
1>          with
1>          [
1>              _Fx=std::_Bind<true,void,std::_Pmf_wrap<void (__thiscall Entity::* )(int),void,Entity,int>,std::_Ph<1> &,int>
1>          ]
1>          c:\users\alec\desktop\c++ code\sfmlproject\sfmlproject\datatables.cpp(78) : see reference to function template instantiation 'std::function<void (Aircraft &)> &std::function<void (Aircraft &)>::operator =<std::_Bind<true,void,std::_Pmf_wrap<void (__thiscall Entity::* )(int),void,Entity,int>,std::_Ph<1> &,int>>(_Fx &&)' being compiled
1>          with
1>          [
1>              _Fx=std::_Bind<true,void,std::_Pmf_wrap<void (__thiscall Entity::* )(int),void,Entity,int>,std::_Ph<1> &,int>
1>          ]

Any possible solutions would be much appreciated.

AlecM
  • 23
  • 1
  • 3
  • 3
    [SSCCE](http://sscce.org) please. How are we supposed to help without knowing anything about the function signatures and types involved? – Praetorian Jan 27 '15 at 03:00
  • Your example is still neither self-contained nor compilable. What is the type of `PickupData::action`? And how do you invoke the `action` later? – Praetorian Jan 27 '15 at 03:13
  • Ok, I edited it again. Sorry, I was really tired yesterday when I typed this originally. Anyway, let me know if you need any more info. – AlecM Jan 28 '15 at 00:37
  • Please try to produce a simple example instead of this code dump. Surely you can reproduce the same error in only a few lines of code. – M.M Jan 28 '15 at 00:43
  • Gerald found a solution to the problem, but I will keep your suggestion in mind if I ever need to ask another question. – AlecM Jan 28 '15 at 11:41

1 Answers1

2

So the problem is with this line:

data[static_cast<int>(Pickup::Type::HealthRefill)].action = 
  std::bind(&Aircraft::repair, _1, 25);

Based on the error dump, action is a std::function<void(Aircraft&)> but repair is a member of the base class Entity rather than Aircraft. Due to the funky return value that std::bind returns, it cannot be cast directly to a std::function<void(Aircraft&)>. You will first need to cast the return value to std::function<void(Entity&)> which can be implicitly cast to std::function<void(Aircraft&)> before assigning it to action. i.e.:

data[static_cast<int>(Pickup::Type::HealthRefill)].action = 
  (std::function<void(Entity &)>) std::bind(&Aircraft::repair, std::placeholders::_1, 25);
Gerald
  • 23,011
  • 10
  • 73
  • 102
  • The placeholder is the this pointer because the initializePickupData function is not a member of Aircraft so it cannot use the this pointer itself. I'm sorry that I did not make this clear before. – AlecM Jan 27 '15 at 23:52
  • @MasterKulon I think this is a VisualStudio bug. Your code compiles on gcc, and I can get it to compile on VS also if I make the following changes `std::function action;` <- note parameter type, pointer, not reference. And then invoke it as `Table[static_cast(type)].action(&player);` – Praetorian Jan 29 '15 at 00:58