python - 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++中最直接的翻译是什么?
解决方案
如果我直接用 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 代码也不太简洁;-)
推荐阅读
- ansible - ansible任务中的`delegate_to`是什么意思?
- postgresql - 在 postgres 中逐行提交
- python - 将数据添加到带有 suplots 的跟踪中,以维护破折号中每个子图的数据拆分
- r - 导入 csv 给出一个只有一个变量的数据框
- python - 数据框:如何在我的一列中执行以下计算?
- javascript - Instagram 自动评论
- ajax - Drupal 8 - Ajax 模式不能从动态创建的链接中工作
- android - 模棱两可的颤振错误:完成错误:Gradle 任务 assembleDebug 失败,退出代码为 1
- python - “as”子句如何影响 Python 中的“import”?
- python - Python 中的滚动 Johansen 协整检验