如何重构此类模板以最小化样板代码?

时间:2012-12-18 13:40:58

标签: c++ templates c++11 refactoring

我最近开始使用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;
}

ANSWER

事实证明,ecatmur的答案在大多数情况下都适用。在我的具体情况下,我将他的解决方案改编为我的实际代码,它在4个案例中有2个工作。在它无法工作的两种情况下,它有点超出了我上面给出的Mickey-Mouse示例的范围。我在SO中找到的最接近的解释是解释我得到的编译时错误可能是this post。问题的关键似乎与我的工作人员代码中发生的事情有关。在两个失败的案例中,我根据我从提升镜像中的运行时反射结果返回的内容,对子类成员进行输出流式处理。我认为这是不可导出的背景的情况。我仍然不明白为什么这两个失败案例中的解决方案完全正常工作(为什么以虚拟方法的形式使用访问者来解决问题)。无论如何,我偶然发现了这种方法并尝试减少代码(在这4种情况下),但在其中两种情况下,如果不进入不可导入的上下文,我就无法真正减少代码问题。

1 个答案:

答案 0 :(得分:4)

可以使用CRTP downcast将

Bar::getValues移至Foo<Bar>

template< typename T >
struct Foo
{
    static std::ostream& GetValues_Worker( std::ostream& os, T const& t )
    {
        // do boost mirror reflection stuff here
        return os;
    }

    std::ostream& getValues( std::ostream& os ) const
    {
        return GetValues_Worker( os, *static_cast<T const *>(this) );
    }
};

此时您可以将两种方法结合起来:

template< typename T >
struct Foo
{
    std::ostream& getValues( std::ostream& os ) const
    {
        T const &t = *static_cast<T const *>(this);
        // do boost mirror reflection stuff here
        return os;
    }
};