Primemaster
Primemaster

Reputation: 312

Using auto specifier in std::function and lambdas

I have a class named Handler which stores some lambdas. What I want to do is to have a std::vector of std::function that stores all my events, for example. I really can't figure out why lambdas doesn't work as I expected.

Here's the handler.h:

class Handler
{
public:
    Handler();
    ~Handler();

    void Register(const char* outcome, std::function<auto()> lambda);
    void Trigger(const char* outcome);

private:
    std::vector<int> identifier;
    std::vector<char*> outcome;
    std::vector<std::function<auto()>> func;
};

And handler.cpp:

Handler::Handler()
{
    //ctor stuff here
}


Handler::~Handler()
{
    this->func.clear();
    this->outcome.clear();
    this->identifier.clear();
    //...
}

void Handler::Register(const char* outcome, std::function<auto()> lambda)
{
    static int identifier = 0;
    identifier++;
    this->outcome.push_back((char*)outcome);
    this->identifier.push_back(identifier);
    this->func.push_back(lambda);
    //Sort outcome
}

void Handler::Trigger(const char * outcome)
{
    int i;
    for (i = 0; i < this->identifier.size(); i++)
    {
        if (!strcmp(outcome, this->outcome.at(i)))
            break;
    }
    this->func[i]();
}

However, if I specify lambdas in a Handler::Register it wont let me throwing no suitable user-defined conversion from "lambda []void ()->void" to "std::function<auto()> exists. In this example I use void return type but other types also error, I don't understand why can't the template from std::function deduce it out, if it is what's happening.

Handler* events = new Handler();

    events->Register("Up", [=]() -> void { //Error here!
        //do stuff
        //return something?
    });

Is there any other way to do this, like without overloading Handler::Register?

Upvotes: 1

Views: 3163

Answers (1)

Caleth
Caleth

Reputation: 62704

auto is not a type, so std::function<auto()> is not a type either. From how you are using it, std::function<void()> is probably what you want.

There are other problems with your code, as noted in the comments, so I would change Handler to this

class Handler
{
public:
    Handler();
    // default ~Handler is fine

    void Register(std::string outcome, std::function<void()> lambda);
    void Trigger(const std::string & outcome outcome) const;
    void Trigger(std::size_t index) const;

private:
    using Outcomes = std::map<std::string, std::function<void()>/*, custom string comparator ?*/>;
    std::vector<Outcomes::iterator> identifier;
    Outcomes outcomes;
};

void Handler::Register(std::string outcome, std::function<void()> func)
{
    auto emplaced = outcomes.emplace(std::move(outcome), std::move(func));
    identifier.push_back(emplaced.first);
}

void Handler::Trigger(const std::string & outcome) const
{
    outcomes.at(outcome)();
}

void Handler::Trigger(std::size_t index) const
{
    identifier[index]->second();
}

Upvotes: 3

Related Questions