我有MyClass
的两个成员函数:
Result MyClass::func1( const CommonParam& commonParam1, const CommonParam& commonParam2, const CommonParam& commonParam3, const ExtraParam1& extraParam1 )
{
Result result;
// prolog code, common to all, using commonParam1, commonParam2, commonParam3
doSomething( 1, commonParam1, commonParam2, extraParam1 );
// epilog code, common to all, using commonParam1, commonParam2, commonParam3
return result;
}
Result MyClass::func2( const CommonParam& commonParam1, const CommonParam& commonParam2, const CommonParam& commonParam3, const ExtraParam2& extraParam2, const ExtraParam3& extraParam3 )
{
Result result;
// prolog code, common to all, using commonParam1, commonParam2, commonParam3
doSomething( 1, commonParam1, commonParam2, extraParam2, extraParam3 );
// epilog code, common to all, using commonParam1, commonParam2, commonParam3
return result;
}
我需要对此进行分解以避免重复prolog / epilog代码,这两个函数完全相同(修改MyClass属性,prolog创建epilog使用的变量......这样的东西)。唯一的区别是调用了不同版本的MyClass::doSomething
(具有不同的参数)。当使用不同的参数集调用doSomething
时,我使用此方法使用模板进行分解并引入辅助类:
class helper1
{
public:
helper1( const ExtraParam1& extraParam1 ) : extraParam1(extraParam1) {}
inline bool compute( MyClass& parent, const CommonParam& commonParam1, const CommonParam& commonParam2 ) const
{
return parent.doSomething( 1, commonParam1, commonParam2, extraParam1 );
}
private:
const ExtraParam1& extraParam1;
};
class helper2
{
public:
helper2( const ExtraParam2& extraParam2, const ExtraParam3& extraParam3 ) : extraParam2(extraParam2), extraParam3(extraParam3) {}
inline bool compute( MyClass& parent, const CommonParam& commonParam1, const CommonParam& commonParam2 ) const
{
return parent.doSomething( 1, commonParam1, commonParam2, extraParam2, extraParam3 );
}
private:
const ExtraParam2& extraParam2;
const ExtraParam3& extraParam3;
};
template<typename Helper>
inline Result funcT( MyClass& parent,
const CommonParam& commonParam1,
const CommonParam& commonParam2,
const CommonParam& commonParam3,
const Helper& helper )
{
// this function is a friend of MyClass, so prolog/epilog can use any private class attribute
Result result;
// prolog code, common to all, using commonParam1, commonParam2, commonParam3
helper.compute( parent, commonParam1, commonParam2 );
// epilog code, common to all, using commonParam1, commonParam2, commonParam3
return result;
}
Result MyClass::func1( const CommonParam& commonParam1, const CommonParam& commonParam2, const CommonParam& commonParam3, const ExtraParam1& extraParam1 )
{
return funcT( *this, commonParam1, commonParam2, commonParam3, helper1( *this, extraParam1) );
}
Result MyClass::func2( const CommonParam& commonParam1, const CommonParam& commonParam2, const CommonParam& commonParam3, const ExtraParam2& extraParam2, const ExtraParam3& extraParam3 )
{
return funcT( *this, commonParam1, commonParam2, commonParam3, helper2( *this, extraParam2, extraParam3 ) );
}
我们的算法会将这些函数调用数十亿次,因此重构必须具有最低的运行时影响。
compute
是inline
,所有内容都通过引用传递,我使用模板而不是虚拟表来最小化运行时影响。但是,我想这会在运行时产生影响(至少我们会创建helper1
,helper2
个对象。
我的重构是否会影响编译器不会删除的运行时影响? 如果是的话,是否有人可以提出具有较低运行时影响的重构?
答案 0 :(得分:2)
我的重构是否会影响编译器不会删除的运行时影响?如果是的话,是否有人可以提出具有较低运行时影响的重构?
确保您不会引入开销的唯一方法是衡量。在重构之前/之后配置代码并检查生成的程序集。
作为附录,这里有一种稍微简单的重构代码的方法,编译器内联仍然很容易。它们不是存储对额外参数的引用,而是完美地转发到通用可调用对象:
template <typename TF, typename... TExtraParams>
Result MyClass::generic_func( const TF& doSomething, const CommonParam& commonParam1, const CommonParam& commonParam2, const CommonParam& commonParam3, const TExtraParams&&... extraParams )
{
Result result;
// prolog code, common to all, using commonParam1, commonParam2, commonParam3
doSomething( 1, commonParam1, commonParam2, std::forward<TExtraParams>(extraParams)... );
// epilog code, common to all, using commonParam1, commonParam2, commonParam3
return result;
}
根据您当前的设计,可以按如下方式使用:
generic_func([](
const CommonParam& a, const CommonParam& b, const CommonParam& c,
const ExtraParam& extra0
)
{
// ... will be called between prolog and epilog
}, my_a, my_b, my_c, extra0);