我有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
对象)。我的重构是否会对运行时产生影响,而编译器不会删除?
如果是,有人可以提出对运行时影响较小的重构吗?
最佳答案
我的重构是否会对运行时产生影响,而编译器不会删除?如果是,有人可以提出对运行时影响较小的重构吗?
确保不引入开销的唯一方法是衡量。在重构之前/之后分析您的代码,并检查生成的程序集。
作为附录,这是重构代码的一种稍微简单的方法,对于编译器来说,内联仍然应该很容易。与其存储对额外参数的引用,不如将它们完美地转发到一个通用的可调用对象:
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);
关于c++ - 可以在不影响运行时间的情况下分解此代码吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/40038668/