简体   繁体   English

Python 返回类型转换为 C++

[英]Python Returning Types Translated to C++

I inherited a bit of code in Python to convert to C++.我继承了 Python 中的一些代码来转换为 C++。 The Python code throws an exception based on a error code returned by other functions. Python 代码根据其他函数返回的错误代码抛出异常。 The Python code uses a utility function called errors(...) that contains creates a dictionary to map error codes to exceptions. Python 代码使用名为errors(...)的实用程序 function,其中包含为 map 创建异常错误代码的字典。 It that returns the type of the exception and the calling code instantiates it with its own message.它返回异常的类型,调用代码用自己的消息实例化它。

class BaseError(Exception):
    pass

class Error1(BaseError):
    pass

class Error2(BaseError):
    pass

def errors(code):
    errors_ = {
        1: BaseError,
        2: Error1,
        3: Error2
    }

    try:
        return errors_[code]
    except KeyError:
        return errors_[1]

def ReturnAnError():
    # Oops an error!
    return 2

try:
    val = ReturnAnError()
    if(val):
        raise errors(val)('{} Failed'.format("Example Failed"))
except BaseError as ex:
    print(ex)

My initial thought is to take an easy path and redefine the Python errors(code) function as void errors(uint8_t code, const char * msg) in c++ and then make a select statement that will throw the exception itself. My initial thought is to take an easy path and redefine the Python errors(code) function as void errors(uint8_t code, const char * msg) in c++ and then make a select statement that will throw the exception itself.

Is there a more elegant or concise solution to translate this code directly?有没有更优雅或更简洁的解决方案来直接翻译这段代码? In particular, what is the most direct translation of raise errors(val)('{} Failed'.format("Example Failed")) in c++?特别是 c++ 中raise errors(val)('{} Failed'.format("Example Failed"))的最直接翻译是什么?

If I directly translate your code in C++:如果我直接在 C++ 中翻译你的代码:

#include <iostream>
#include <string>
#include <map>

class BaseError {
  public:
    BaseError(std::string s) : msg(s) {}
    virtual ~BaseError() {} // useless because inherited classes do not have attribute to delete
    friend std::ostream & operator<<(std::ostream & out, const BaseError & e) {
       out << e.msg;
       return out;
    }
    static BaseError * mk(std::string s) { return new BaseError(s); }
  private:
    std::string msg;
};

class Error1 : public BaseError {
  public:
    Error1(std::string s) : BaseError(s) {}
    static BaseError * mk(std::string s) { return new Error1(s); }
};

class Error2 : public Error1 {
  public:
    Error2(std::string s) : Error1(s) {}
    static BaseError * mk(std::string s) { return new Error2(s); }
};

typedef BaseError * (*fmk)(std::string);

fmk errors(int code) 
{
  const static std::map<int, fmk> error = {
       {1, &BaseError::mk},
       {2, &Error1::mk},
       {3, &Error2::mk}
  };
  std::map<int, fmk>::const_iterator it = error.find(code);
  
  return ((it == error.end()) ? error.find(1) : it)->second;
}

int ReturnAnError()
{
  // Oops an error!
  return 2;
}


int main()
{
  try {
    int val = ReturnAnError();
  
    if (val)
      throw (errors(val))("blah blah");
  }
  catch (BaseError * ex) {
      std::cout << *ex << std::endl;
      delete ex;
  }
}    

Compilation and execution:编译和执行:

pi@raspberrypi:/tmp $ g++ c0.cc
pi@raspberrypi:/tmp $ ./a.out
blah blah
pi@raspberrypi:/tmp $ 

About the function errors :关于 function错误

  • The Python dictionary can be translated to C++ std::map Python字典可以翻译成C++ std::map

  • As I know contrarily to Python I cannot put in the std::map the address of the constructor of each class, this is why I used a static operation mk for each class. As I know contrarily to Python I cannot put in the std::map the address of the constructor of each class, this is why I used a static operation mk for each class.

  • To avoid to create the std::map each time errors is called I defined error static (and const to clearly indicate I do not want to modify it), but this is an optimization and this is not mandatory.为了避免在每次调用错误时创建std::map ,我定义了错误static (和const以清楚地表明我不想修改它),但这是一种优化,这不是强制性的。

  • In Python the exceptions are very used, this is less the case in C++, this is why I use an iterator to know if the code is a known key, and I test it.在 Python 中异常使用非常多,在 C++ 中这种情况较少,这就是为什么我使用迭代器来了解代码是否是已知键,并对其进行测试。

To have a way to print the instances of the classes I overloaded the operator<< , anyway that does not allow to check the program created an Error1 , and even I change the code to have:为了有办法打印类的实例,我重载了operator<< ,无论如何不允许检查程序创建了Error1 ,甚至我将代码更改为:

  try {
    int val = ReturnAnError();
  
    if (val)
      throw (errors(val))("blah blah");
  }
  catch (Error2 * ex) {
      std::cout << "err2" << *ex << std::endl;
      delete ex;
  }
  catch (Error1 * ex) {
      std::cout << "err1" << *ex << std::endl;
      delete ex;
  }
  catch (BaseError * ex) {
      std::cout << *ex << std::endl;
      delete ex;
  }

the executed code will be catch (BaseError * ex) {...}执行的代码将被catch (BaseError * ex) {...}

If I do:如果我做:

  try {
    int val = ReturnAnError();
  
    if (val)
      throw *(errors(val))("blah blah");
  }
  catch (Error2 & ex) {
      std::cout << "err2" << ex << std::endl;
  }
  catch (Error1 & ex) {
      std::cout << "err1" << ex << std::endl;
  }
  catch (BaseError & ex) {
      std::cout << ex << std::endl;
  }

again the executed code will be catch (BaseError & ex) {...} (and I created a memory leak).再次执行的代码将被catch (BaseError & ex) {...} (我创建了一个 memory 泄漏)。

So a virtual operation is needed to differentiate the classes when pritting, for instance:所以在打印时需要一个virtual操作来区分类,例如:

#include <iostream>
#include <string>
#include <map>

class BaseError {
  public:
    BaseError(std::string s) : msg(s) {}
    virtual ~BaseError() {} // useless because inherited classes do not have attribute to delete
    virtual void print(std::ostream & out) const { out << msg; }
    static BaseError * mk(std::string s) { return new BaseError(s); }
  private:
    std::string msg;
};

class Error1 : public BaseError {
  public:
    Error1(std::string s) : BaseError(s) {}
    virtual void print(std::ostream & out) const { 
      out << "error1 ";
      BaseError::print(out);
    }
    static BaseError * mk(std::string s) { return new Error1(s); }
};

class Error2 : public Error1 {
  public:
    Error2(std::string s) : Error1(s) {}
    virtual void print(std::ostream & out) const { 
      out << "error2 ";
      BaseError::print(out);
    }
    static BaseError * mk(std::string s) { return new Error2(s); }
};

typedef BaseError * (*fmk)(std::string);

fmk errors(int code) 
{
  const static std::map<int, fmk> error = {
       {1, &BaseError::mk},
       {2, &Error1::mk},
       {3, &Error2::mk}
  };
  std::map<int, fmk>::const_iterator it = error.find(code);
  
  return ((it == error.end()) ? error.find(1) : it)->second;
}

int ReturnAnError()
{
  // Oops an error!
  return 2;
}


int main()
{
  try {
    int val = ReturnAnError();
  
    if (val)
      throw (errors(val))("blah blah");
  }
  catch (BaseError * ex) {
      ex->print(std::cout);
      std::cout << std::endl;
      delete ex;
  }
}    

Compilation and execution:编译和执行:

pi@raspberrypi:/tmp $ g++ c.cc
pi@raspberrypi:/tmp $ ./a.out
error1 blah blah
pi@raspberrypi:/tmp $ 

Is there a more elegant or concise solution有没有更优雅或更简洁的解决方案

To be frank this is at least not concise, but your Python code is not too;-)坦率地说,这至少不简洁,但是您的 Python 代码也不是太简洁;-)

One function, exactly same name and same types of each param, cannot have two return types.一个 function,每个参数的名称和类型完全相同,不能有两种返回类型。 So there is no way allow errors return different type of exceptions.所以没有办法允许errors返回不同类型的异常。 ie errors cannot be exactly translated.errors不能准确翻译。

But for raise errors(val)("...") , one simple way is throw the exception in errors .但是对于raise errors(val)("...") ,一种简单的方法是在errorsthrow异常。 sample code:示例代码:

#include <string>
class BaseError {
public:
    std::string s;
    BaseError(const std::string &_s):s(_s){}
};
class Error1 : public BaseError {
public:
    Error1(const std::string &s):BaseError(s){}
};
class Error2 : public BaseError {
public:
    Error2(const std::string &s):BaseError(s){}
};

void errors(int val, const std::string &s)
{
    switch(val)
    {
    case 1:
        throw BaseError(s);
    case 2:
        throw Error1(s);
    case 3:
        throw Error2(s);
    default:
        throw BaseError(s);
    }
}

Or if needed an object can throw in other where, one way is that creating a class can throw exceptions.或者,如果需要, object可以在其他地方throw ,一种方法是创建class可以throw异常。 sample code:示例代码:

class errors {
public:
    int val;
    std::string s;
    errors(int _val, const std::string _s): val(_val), s(_s){}
    void raise()
    {
        switch(val)
        {
        case 1:
            throw BaseError(s);
        case 2:
            throw Error1(s);
        case 3:
            throw Error2(s);
        default:
            throw BaseError(s);
        }
    }
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM