我最近开始使用boost mirror进行 ORM 反射,这样我就可以最大限度地减少与 DB 相关的样板代码的数量。
下面列出了我遇到的一种模式。
由于Bar
' 的代码即使对于 ' 看起来也一样Baz
,所以我想知道,是否有可能进一步折叠此代码?
如果getValues()
接口看起来一样就好了,但是同样的实现也可以存在Foo
。
#include <iostream>
template< typename T >
struct Foo
{
static std::ostream& GetValues_Worker( std::ostream& os, T const& t )
{
// do boost mirror reflection stuff here
return os;
}
};
struct Bar :
public Foo<Bar>
{
// REFACTOR IF POSSIBLE: this code will always look the same - even for Baz
std::ostream&
getValues( std::ostream& os ) const
{
return GetValues_Worker( os, *this );
}
};
struct Baz :
public Foo<Baz>
{
// REFACTOR IF POSSIBLE: looks the same as Bar
std::ostream&
getValues( std::ostream& os ) const
{
return GetValues_Worker( os, *this );
}
};
int main( int argc, char* argv[] )
{
Bar b;
std::cerr << b.getValues( std::cerr ) << std::endl;
}
回答
事实证明,ecatmur 下面的答案在大多数情况下都有效。在我的具体情况下,我将他的解决方案改编为我的真实代码,它适用于 4 个案例中的 2 个。在这两种失败的情况下,它有点超出了我上面给出的米老鼠示例的范围。我可以在 SO 中找到的最接近的解释解释了我得到的编译时错误可能是这篇文章。问题的症结似乎与我的Worker 代码中发生的事情有关。在这两个失败的案例中,我正在根据我从运行时反射返回的结果对子类成员进行输出流式处理,结果是boost mirror。我认为这是一个不可演绎的情况. 我仍然不明白为什么这两个失败案例中的解决方案完全有效(为什么使用虚拟方法形式的访问者可以解决这个问题)。无论如何,我偶然发现了这种方法,并试图进一步减少代码(在这 4 种情况下),但在其中两种情况下,如果不遇到不可演绎的上下文问题,我就无法真正减少代码了。