首页 > 解决方案 > Python 返回类型转换为 C++

问题描述

我在 Python 中继承了一些代码来转换为 C++。Python 代码根据其他函数返回的错误代码引发异常。Python 代码使用一个名为 contains 的实用函数errors(...)创建一个字典来将错误代码映射到异常。它返回异常的类型,调用代码用自己的消息实例化它。

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)

我最初的想法是走一条简单的路,errors(code)像在 c++ 中一样重新定义 Python 函数 void errors(uint8_t code, const char * msg),然后创建一个会抛出异常本身的 select 语句。

有没有更优雅或更简洁的解决方案来直接翻译这段代码?特别是,raise errors(val)('{} Failed'.format("Example Failed"))c++中最直接的翻译是什么?

标签: pythonc++code-translation

解决方案


如果我直接用 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;
  }
}    

编译和执行:

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

关于功能错误

  • Python字典可以翻译成C++std::map

  • 正如我所知道的与 Python 不同,我不能输入std::map每个类的构造函数的地址,这就是为什么我对每个类都使用静态操作mk的原因。

  • 为了避免在std::map每次调用错误时创建错误,我定义了错误 static(并const清楚地表明我不想修改它),但这是一种优化,这不是强制性的。

  • 在 Python 中,异常非常常用,而在 C++ 中则较少,这就是为什么我使用迭代器来了解代码是否是已知键,并对其进行测试。

为了有办法打印我重载的类的实例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;
  }

执行的代码将是catch (BaseError * ex) {...}

如果我做 :

  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;
  }

再次执行的代码将是catch (BaseError & ex) {...}(并且我创建了内存泄漏)。

所以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;
  }
}    

编译和执行:

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

有没有更优雅或更简洁的解决方案

坦率地说,这至少不够简洁,但您的 Python 代码也不太简洁;-)


推荐阅读