3

I have functions in a superclass designed to associate a string with internal functions:

class Base
{
    typedef std::function<void(double)> double_v;

    bool registerInput(std::string const& key, double_v const& input) {
        functions[key] = input;
    }

    void setInput(std::string key, double value) {
        auto fit = functions.find(key);
        if (fit == functions.end()) return;

        fit->second(value);
    }

    std::map<std::string, double_v> functions;
}

The idea being that any subclass I can register functions can call them with a string and value:

SubBase::SubBase() : Base(){
    Base::registerInput(
        "Height", 
        static_cast<void (*)(double)>(&SubBase::setHeight)
    );
}

void SubBase::setHeight(double h) {
....
}

Which could then be called with:

subBaseInstance.setInput("Height", 2.0);

However when I compile I'm getting the following error:

In constructor ‘SubBase::SubBase()’
error: invalid static_cast from type ‘<unresolved overloaded function type>’ to type ‘void (*)(double)’

What am I missing?

salmonmoose
  • 137
  • 2
  • 10

3 Answers3

4

As others noted, the types doesn't match. However you could use std::bind for it to work:

Base::registerInput(
    "Height", 
    std::bind(&SubBase::setHeight, *this, std::placeholders::_1)
);
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • Maybe worth mentioning that the function type should be `std::function`... – Kerrek SB Sep 06 '12 at 07:19
  • In my quest to make this more generic, I tried both this and ForEveR's answer, and both ended up with the same error message as my original problem. – salmonmoose Sep 10 '12 at 05:13
1
typedef std::function<void(double)> double_v;

It's function-pointer.

static_cast<void (*)(double)>(&SubBase::setHeight)

It's member-function pointer. They are not convertible to each other.

You can use std::bind for this

SubBase::SubBase() : Base(){
    Base::registerInput(
        "Height", 
        std::bind(&SubBase::setHeight, this, std::placeholders::_1)
    );
ForEveR
  • 55,233
  • 2
  • 119
  • 133
1

SubBase is not static, so it has an implicit first argument of SubBase* (the object you call the member function for). Hence the signature is void (*) (SubBase*, double). In C++11 you can probably (I'm not completely sure) cast it to a function<void (SubBase*, double)>.

Using lambda functions, you can do the following:

SubBase::SubBase() : Base(){
    auto myself = this;
    Base::registerInput( 
        "Height",  
        [myself] (double v) { myself->setHeight (v); }
    ); 
} 

void SubBase::setHeight(double h) { 
.... 
} 
JohnB
  • 13,315
  • 4
  • 38
  • 65
  • This indeed works perfectly - is it trivial to extend this to work for functions that accept other data types (int) (Base*)? – salmonmoose Sep 09 '12 at 02:06
  • there are often more than one type a method can accept, basic types like double, int and unsigned, but subclasses of Base can feed back into themselves - something along the lines of: [myself](int v){myself->setHeight(v);} [myself](SubBase2 v){myself->setHeight(v);} There are appropriate methods, but storing them in the same map seems to be working against the language. – salmonmoose Sep 09 '12 at 13:32
  • Never mind - I was trying to be too clever - far easier to just keep maps of different input types. – salmonmoose Sep 10 '12 at 03:39