我有100个左右的蹦床功能.我想知道是否可以在try / catch块中自动包装每个.
请提前通知,这不是一个简单的问题.我将从描述(简化)代码的问题开始,然后尝试在下面尽可能地回答它,以便读者可以看到我在哪里.
Foo有一个函数指针表:
编辑:这是一个C函数指针表.所以它可以接受静态W :: w.
签名在这里:http://svn.python.org/projects/python/trunk/Include/object.h
编辑:我试过一个测试用例here:
class Foo { Table table; Foo() { // Each slot has a default lambda. : table->fp_53 = [](S s,A a,B b) -> int {cout<<"load me!";}; table->fp_54 = [](S s,C c,D d,E e) -> float {cout<<"load me!";}; // ^ Note: slots MAY have different signatures // only the first parameter 'S s' is guaranteed } // Foo also has a method for loading a particular slot: : void load53() { table->fp_53 = func53; } void load54() { table->fp_54 = func54; } : }
如果某个特定的插槽是“已加载”,则会将其加载到其中:
int func53(S s,B b) { try{ return get_base(s)->f53(a,b); } catch(...) { return 42;} } float func54(S s,E e) { try{ return get_base(s)->f54(c,d,e); } catch(...) { return 3.14;} }
我试图使用lambdas来实现这一点,以便绕过必须分别定义所有这些func53.像这样的东西:
class Foo { : void load53() { table->fp_53 = [](S s,B b)->int { return get_base(s)->f53(a,b); } } void load54() { table->fp_54 = [](S s,E e)->float { return get_base(s)->f54(c,e); } }
但是,这无法捕获错误.我需要在return语句周围添加一个try / catch:
try{ return get_base(s)->f53(a,b); } catch{ return 42; }
然而,这会造成很多混乱.如果我能这样做会很好:
return trap( get_base(s)->f53(a,b); )
我的问题是:有没有办法编写这个陷阱函数(不使用#define)?
这是我到目前为止所提出的:
我认为这会传递所有必要的信息:
trap<int,&Base::f53>(s,a,b)
陷阱的定义可能如下所示:
template<typename RET,Base::Func> static RET trap(S s,...) { try { return get_base(s)->Func(...); } catch { return std::is_integral<RET>::value ? (RET)(42) : (RET)(3.14); } }
这可能允许非常干净的语法:
class Foo { : void load53() { table->fp_53 = &trap<int,&Base::f53>; } void load54() { table->fp_54 = &trap<float,&Base::f54>; } }
在这一点上,我甚至不确定是否违反了某些法律. table-> fp_53必须是有效的C函数指针.
传递非静态成员函数(& Base :: f53>)的地址不会违反此规则,因为它是模板参数,并且不会影响陷阱的签名
同样,……应该没问题,因为C允许varargs.
所以,如果这确实有效,可以清理吗?
我的想法是:
1)也许……应该作为包移回模板参数.
2)也许可以推导出陷阱的返回类型,并保存一个模板参数
3)Base :: Func模板参数是非法语法.我怀疑它甚至不接近合法的东西.这可能会破坏整个方法.
解决方法
#include <utility> template <typename T,T t> struct trap; template <typename R,typename... Args,R(Base::*t)(Args...)> struct trap<R(Base::*)(Args...),t> { static R call(int s,Args... args) { try { return (get_base(s)->*t)(std::forward<Args>(args)...); } catch (...) { return std::is_integral<R>::value ? static_cast<R>(42) : static_cast<R>(3.14); } } };
用法:
table->fp_53 = &trap<decltype(&Base::f53),&Base::f53>::call; table->fp_54 = &trap<decltype(&Base::f54),&Base::f54>::call;
注意:虽然Args本身不是转发引用,但仍可以使用std :: forward.