std :: function

时间:2015-07-06 11:44:53

标签: c++11 variadic-templates

最近,我一直在和我的c ++ game-dev引擎一起做一个小项目:它是一种用C ++编写的编程语言,在一个名为kickC的标题中。以下是我到目前为止所做的事情:(见下面的问题)

#ifndef KICK_C_INCLUDED_H
#define KICK_C_INCLUDED_H
#include <iostream>
#include <string>
#include <sstream>
#include <algorithm>
#include <cctype>
#include <exception>
#include <functional>
#include <unordered_map>
#include <vector>
#define LOG(x) std::cout << x << std::endl;

namespace strutil
{
    inline unsigned CountWords(const std::string& value){
        std::string temp = value;
        std::replace_if(temp.begin(), temp.end(), std::ptr_fun<int, int>(std::isspace), ' ');
        temp.erase(0, temp.find_first_not_of(" "));
        if(temp.empty())
            return 0;
        return std::count(temp.begin(), std::unique(temp.begin(), temp.end()), ' ') + !std::isspace(*value.rbegin());
    }
}

class KickCException : std::exception
{
public:
    explicit KickCException(const char* msg, bool fatal = false)
        :   msg_(msg){}
    explicit KickCException(const std::string& msg)
        : msg_(msg){}
    virtual ~KickCException() throw(){}
    virtual const char* what() const throw(){
        return std::string("[error :] [")
            .append(msg_)
            .append("]")
            .c_str();
    }
protected:
    std::string msg_;

};
class KickCFileException : KickCException
{
public:
    explicit KickCFileException(const char* msg)
        : KickCException(msg){}
    explicit KickCFileException(const std::string& msg)
        : KickCException(msg){}
    virtual ~KickCFileException() throw(){}
    const char* what() const throw() override{
        return std::string("[file error :] [")
            .append(msg_)
            .append("]")
            .c_str();
    }
};
class KickCEmptyStringException : KickCException
{
public:
    explicit KickCEmptyStringException(const char* msg)
        : KickCException(msg){}
    explicit KickCEmptyStringException(const std::string& msg)
        : KickCException(msg){}
    virtual ~KickCEmptyStringException() throw(){}
    const char* what() const throw() override{
        return std::string("[empty string error :] [")
            .append(msg_)
            .append("]")
            .c_str();
    }
};


class KickCAPIBehaviourImplementation
{
public:
    KickCAPIBehaviourImplementation(){}
    ~KickCAPIBehaviourImplementation(){}

    void AddDefined(const std::string& str, std::function<void(void)> func){
        m_values[str] = func;
    }
    void ParseAndApplyLine(const std::string& line){
        std::istringstream iss(line);

        for(unsigned i = 0; i < strutil::CountWords(line); ++i){
            static std::string word = "";
            iss >> word;
            for(auto it_map = m_values.begin(); it_map != m_values.end(); ++it_map){
                if(it_map->first == word)
                {
                    (it_map->second)(/*HERE ! GIVE SOME ARGUMENTS ! */);
                }
            }
        }
    }
private:
    std::unordered_map<std::string, std::function<void(void)>> ///so far, args is void... m_values;
};

#endif //KICK_C_INCLUDED_H

/// SRC

int main(int argc, const char** args){
    std::ifstream file("script.kick");
    KickCAPIBehaviourImplementation kickCApiBehaviour;
    try{
        if(!file.is_open())
            throw KickCFileException("unvalid fileName taken at input");
        kickCApiBehaviour.AddDefined("print", [&](void){std::cout << "print found !" << std::endl;});
        while(!file.eof()){
            std::string line;
            std::getline(file, line);
            kickCApiBehaviour.ParseAndApplyLine(line);
        }
    }catch(KickCException& e){
        LOG(e.what());
    }
    file.close();
  std::cin.get();
}

所以这里是问题:我想传递std :: function(参见类KickCAPIBehaviourImplementation类型的变量参数:当然,我需要使用变量模板但问题是如何实现它,所以我最终调用我的函数?

kickCApiBehaviour.AddDefined("print", [&](int arg1, char * arg2, int arg3){std::cout << arg1 << arg2 << arg3 << std::endl;});

1 个答案:

答案 0 :(得分:2)

将解析器移动到std::function

添加功能的地方,请包含签名:

// helper type:
template<class T>struct tag{using type=T;};

kickCApiBehaviour.AddDefined(
  "print", // the name
  tag<void(int,char*,int)>{}, // the signature
  [&](int arg1, char * arg2, int arg3){
    std::cout << arg1 << arg2 << arg3 << std::endl;
  } // the operation
);

存储std::function< error_code(ParserState*) >。在AddDefined内,存储一个lambda,其中包含对代码的调用,该代码解析参数并调用传入的lambda:

template<class R, class...Args, class F>
void AddDefined(std::string name, tag<R(Args...)>, F f) {
  std::function< error_code(ParserState*) > r =
    [f](ParserState* self)->error_code {
      // here, parse each of Args... out of `self`
      // then call `f`.  Store its return value,
      // back in `self`.  If there is a parse error (argument mismatch, etc),
      // return an error code, otherwise return no_error
    };
  m_values[name] = r;
};

然后m_values包含操作“获取解析器状态,并解析参数,并在其上调用有问题的函数”。