【问题标题】:recursive template inheritance code duplication递归模板继承代码重复
【发布时间】:2014-07-18 20:04:15
【问题描述】:
#include <iostream>

template< class T, unsigned S >
struct my_iterator;

template< class T >
struct my_iterator< T, 1 >
{ 
    T* p;
};

template< class T, unsigned S >
struct my_iterator : my_iterator< T, S / 2 >
{
    static_assert ((S & (S - 1)) == 0, "S must be a power of 2");

    using my_iterator< T, S / 2 >::p;

    unsigned burp() {return (*p) + S;}
};

int main()
{
    int v = 10;

    my_iterator< int, 8 > a;
    a.p = &v;
    std::cout << a.burp() << std::endl;

    my_iterator< int, 4 >& b = a;
    std::cout << b.burp() << std::endl;

    my_iterator< int, 1 > c;
    c.p = &v;
    std::cout << c.burp() << std::endl; // error: no member named 'burp'

    return 0;
}

这将修复错误:

template< class T >
struct my_iterator< T, 1 >
{ 
    unsigned burp() {return (*p) + 1;}

    T* p;
};

但在我的真实代码中,我有很多方法,不仅仅是burp,它们都依赖于Sp,它们都需要实现两次,一次在通用类中,一次在专业类中。有什么办法可以避免重复代码?我看到了这个类似的问题:

Avoiding code duplication in a specialized template

但答案在我的情况下不起作用,因为我最终会得到许多 p 的副本,在递归层次结构的每一层都有一个。

【问题讨论】:

    标签: c++ templates


    【解决方案1】:

    另一种选择,如果您想继续使用递归停止值 1,您可以将停止值移动到 0...
    这样my_iterator&lt;T,1&gt; 仍然有默认实现。

        template< class T, unsigned S >
        struct my_iterator;
    
        template< class T >
        struct my_iterator< T, 0 >
        { 
            T* p;
    
        };
    
        template< class T, unsigned S >
        struct my_iterator : my_iterator< T, S / 2 >
        {
            static_assert ((S & (S - 1)) == 0, "S must be a power of 2");
    
            using my_iterator< T, S / 2 >::p;
    
            unsigned burp() {return (*p) + S;}
        };
    

    【讨论】:

    • 这么简单的解决方案,谢谢!此外,在这种情况下,无论如何我都不希望能够调用任何带有 S==0 的方法,这是没有意义的,所以这很完美。
    【解决方案2】:

    另一种方法是在其他结构中移动特定的东西:

    template <typename T> struct opt_ptr { T* p; };
    
    // to be able to use std::conditional with non instantiated type.
    template <typename T> struct identity { using type = T; };
    
    template<typename T, unsigned S>
    struct my_iterator :
        std::conditional<S == 1,
                         identity<opt_ptr<T>>,
                         identity<my_iterator<T, S / 2>>>::type::type
    {
        static_assert ((S & (S - 1)) == 0, "S must be a power of 2");
    
        using opt_ptr<T>::p; // Note that you may use this->p to avoid this line
    
        unsigned burp() {return *p + S;}
        // Other methods using S and p.
    };
    

    【讨论】:

    • my_iterator&lt;T, 0&gt;自继承也是个问题。
    • @atb: 只有opt_ptr&lt;T, 1&gt;T* p;,其他都是空类。
    • 什么会阻止递归继承?难道我还不需要 my_iterator 或 my_iterator 的特化吗?
    • @atb:你说得对,递归必须用空的my_iterator&lt;T, 0&gt;... (或使用其他技巧进行条件继承)
    【解决方案3】:

    您可以将 S 传递给基本模板,然后将方法移到那里。

    template< class T, unsigned S, unsigned N >
    struct my_iterator;
    
    template< class T, unsigned S >
    struct my_iterator< T,S, 1 >
    {  
        unsigned burp() {return (*p) + S;}
    
        T* p;
    };
    
    template< class T, unsigned S, unsigned N = S >
    struct my_iterator : my_iterator< T, S, N / 2 >
    {
        static_assert ((S & (S - 1)) == 0, "S must be a power of 2");
    
        using my_iterator< T,S, N / 2 >::p;
    
    };
    

    【讨论】:

    • 您还必须重新定义基本模板以采用三个参数。
    • @atb 好的,我已经打开了我的 VS 以获得我的意思的编译版本。
    • 这确实避免了重复但它改变了功能。我不能再将my_iterator&lt; int, 8 &gt; 转换为my_iterator&lt; int, 4 &gt;,这是设计的要求。我可以将其转换为my_iterator&lt; int, 8, 4 &gt;,但 burp 返回错误值。
    • @atb 你需要一直递归到 1 吗?
    • 是的,我愿意。我知道我可以使用reinterpret_cast 在没有任何继承的情况下获得相同的功能,但我正试图以“正确”的方式做到这一点。我正在尝试使用额外的非专业基类和std::conditional 的条件继承来解决问题……但到目前为止还没有运气。
    猜你喜欢
    • 2016-03-18
    • 2023-03-04
    • 1970-01-01
    • 1970-01-01
    • 2012-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多