【问题标题】:Generic Buffer with fancy swap function? How?具有花哨交换功能的通用缓冲区?如何?
【发布时间】:2012-11-08 23:11:03
【问题描述】:

我今天早上遇到了这个问题:

我想构建一个通用类 FrontBackBuffer,我可以将其用作以下(一些示例)。

编辑删除了一些令人困惑的部分!

int bb=10;
int fb=3;
FrontBackBuffer< const int*, int & > buf(&fb, &bb);
buf.getBack() = 4; // change from 10 to 4
// buf.getFront() = 5; NO! is const!

buf.swap();
//NOW getFront() and getBack() should return  4 and 3!

FrontBackBuffer< int, const & int > buf(14, bb);
buf.getBack() = 5; // change from 4 to 5
// buf.getFront() = 5; NO! is const!

buf.swap();   
//NOW getFront() and getBack() should return  5 and 14!

它存储两个缓冲区,应该是相同的底层类型(参见 static_assert)。 这些缓冲区可以是指针类型或引用类型,也可以是 const 或非 const。 它有两个函数getFront()getBack()。这些函数总是返回对底层缓冲区的引用,无论是常量还是非常量。这就是为什么会有各种各样的MyRefTypes 特征特殊化。

目前工作的类如下:

template< typename TBufferTypeFront, typename TBufferTypeBack = TBufferTypeFront>
class FrontBackBuffer {

// If <const * int , int&> --> this result in is_same< int , int > 
// STATIC_ASSERT( std::is_same< RemoveModifiers<TBufferTypeFront>::type, typename RemoveModifiers<TBufferTypeFront>::type>::result )

public:

    template <typename T>
    struct MyRefTypes {
        typedef const T & Con;
        typedef T& Ref;
        typedef const T& CRef;
        static Ref getRef(T& v) {
            return v;
        }
    };

//Specialization for Reference
    template <typename T>
    struct MyRefTypes<T&> {
        typedef T & Con;
        typedef T& Ref;
        typedef const T& CRef;
        static inline Ref getRef(T& v) {
            return v;
        }
    };

//Specialization for const Reference
    template <typename T>
    struct MyRefTypes<const T&> {
        typedef const T & Con;
        typedef const T& Ref;
        typedef const T& CRef;
        static inline Ref getRef(const T& v) {
            return v;
        }
    };

//Specialization for const
    template <typename T>
    struct MyRefTypes<const T> {
        typedef const T & Con;
        typedef const T& Ref;
        typedef const T& CRef;
        static inline Ref getRef(const T& v) {
            return v;
        }
    };

//Specialization for pointers
    template <typename T>
    struct MyRefTypes<T*> {
        typedef T* Con;
        typedef T& Ref;
        typedef T* const CRef;  //! note this is a pointer....
        static inline Ref getRef(T* v) {
            return *v;
        }
    };

//Specialization for const pointers
    template <typename T>
    struct MyRefTypes<const T*> {
        typedef const T* Con;
        typedef const T& Ref;
        typedef const T* const CRef; //! note this is a pointer....
        static inline Ref getRef(const T* v) {
            return *v;
        }
    };


    typedef typename MyRefTypes<TBufferTypeFront>::Ref TBufferTypeFrontRef;
    typedef typename MyRefTypes<TBufferTypeFront>::CRef TBufferTypeFrontCRef;
    typedef typename MyRefTypes<TBufferTypeFront>::Con TBufferTypeFrontCon;

    typedef typename MyRefTypes<TBufferTypeBack >::Ref TBufferTypeBackRef;
    typedef typename MyRefTypes<TBufferTypeBack >::CRef TBufferTypeBackCRef;
    typedef typename MyRefTypes<TBufferTypeBack >::Con TBufferTypeBackCon;

    explicit FrontBackBuffer(
        TBufferTypeFrontCon  front,
        TBufferTypeBackCon   back):
        m_Front(front),
        m_Back(back)
    {
             m_pBack = (void*)&m_Back;
             m_pFront = (void*)&m_Front;

    };


    ~FrontBackBuffer()
    {};

    TBufferTypeFrontRef getFront() {
        return MyRefTypes<TBufferTypeFront>::getRef(m_Front);
    }
    TBufferTypeBackRef getBack() {
        return MyRefTypes<TBufferTypeBack>::getRef(m_Back);
    }
    private:

    void swap(){
         void * temp = m_pFront;
         m_pFront = m_pBack;
         m_pBack = temp;
    }

    TBufferTypeFront * m_pFront;       ///< The pointer to front buffer
    TBufferTypeBack * m_pBack;         ///< The pointer to back buffer

    TBufferTypeFront m_Front;       ///< The front buffer
    TBufferTypeBack m_Back;         ///< The back buffer

};

现在的问题是(我不能完全正确地解决): 如何添加通用函数 swap() 来交换缓冲区,但不应复制。我考虑了两个指针void * m_pFrontvoid *m_pBack,我应该用它们来完成这项工作,并正确分配(参见构造函数)。

但我现在如何编写这些 getter 函数对我来说是个谜:

    TBufferTypeFrontRef getFront() {
        return MyRefTypes<TBufferTypeFront>::getRef(m_Front);
    }
    TBufferTypeBackRef getBack() {
        return MyRefTypes<TBufferTypeBack>::getRef(m_Back);
    }

归根结底,它应该可以工作 :-) 感谢您的帮助并尝试解决这个难题:-)!

【问题讨论】:

  • 只有当frontback相同或者它们的指针可以相互转换时,你才能交换它们。请注意,swap 在标准库中具有非常特定的含义,并且与您的含义不同。除此之外,你想要实现的目标对我来说似乎不是很有用,但我可能缺乏上下文。
  • swap 应该做同样的事情,在内部它应该切换缓冲区,不过是一个高效的...
  • 我也很困惑你想要完成什么。我假设您知道如果缓冲区的类型不同,则不能交换缓冲区?如果这是正确的,为什么不只存储一个关于它们是否被交换之类的变量。
  • 是的,这有点令人困惑,但是如果查看应该如何使用该类的行为,它应该会变得很清楚,下面只是试图实现这一点的一个实现。它可以在没有交换功能的情况下工作......问题是这个缓冲区基本上可以保存自己的内存或引用其他内存(指针或引用),前后都有,这正是好东西,你可以使用它非常通用,它仍然可以做到!但是交换功能是一个难题。这个类只是为了模板的乐趣,可能有点矫枉过正,但不是很好吗?
  • 这感觉像是一个错误的设计。简而言之,您的类不是缓冲区,而是指针/引用容器。也许最好解释一下您要完成什么任务以及为什么不能使用std::pair 的指针来完成它,而交换是由std::swap(p.first, p.second) 实现的?它非常有效(移动 24B)并且显然也可以满足您的需求。为什么缓冲区的类型如此重要?为什么值得编写一个全新的容器模板?

标签: c++ templates template-specialization traits


【解决方案1】:

我必须承认我真的不明白为什么你需要你发布的所有代码来完成你描述的任务,但我可能遗漏了一些东西。但是考虑到您只想以通用但有效的方式交换两个相同类型的缓冲区,我建议如下:

template<typename BufferType>
class FrontBackBuffer
{
private:
    BufferType buffers[2];
    int _back,_front;
public:
/*
omitting copy constructors, operators etc for brevity
*/
    FrontBackBuffer()
        : _front(0), _back(1)
    {
         /*
           You can also start with front and back pointing to the same memory it is of no  importance if you remember to swap them once or if you just set the back buffer and never the front
         */
    }
    BufferType & getFront()
    {
        return buffers[_front];
    }
    BufferType & getBack()
    {
        return buffers[_back];
    }
    void swap()
    {
        _front = _back;
        _back = (_front + 1) % 2;
    }
};

你可以这样使用它:

int intArray[] = {1,2,3,4};

FrontBackBuffer<int*> intPtrBuffers;
intPtrBuffers.getBack() = new int[4];
intPtrBuffers.getFront() = new int[4];

memcpy(intPtrBuffers.getBack(), intArray, sizeof(intArray));
intPtrBuffer.swap();

【讨论】:

  • 这是另一种方式,但不允许我单独定义后部和前部,如果您想将前缓冲区放在其他地方怎么办:-)?不是您的 FrontBackBuffer 中的成员实例 :-)
  • @Gabriel 感谢您的评论。正如我所写 - 我可能不了解您的真正需求。您编写的缓冲区是相同类型的,所以对我来说使用两种类型:一种用于背面,一种用于正面可能非常通用,但只会使代码不清楚。如果您想将它们保存在其他地方,那么您可以随时使用指针。我喜欢让事情变得简单。但是,您的真正需求可能确实需要更复杂的东西。 (附带说明:我真的很想知道什么样的实现需要不同类型的前后缓冲区?)
【解决方案2】:

这是完整的答案!

代码有效,缓冲区是通用的 :-) --> http://ideone.com/m3kFmo

而且交换功能也很高效,可以按需要工作!

当然,这个类只有在底层类型相同时才有用,例如: FrontBackBuffer&lt; int *, int &amp;&gt; --> 好的

FrontBackBuffer&lt; int *, const double &amp;&gt; --> 没问题,但是swap函数就没意义了!

这里是代码! :-)

template< typename TBufferTypeFront, typename TBufferTypeBack = TBufferTypeFront>
class FrontBackBuffer {

    // If <const * int , int&> --> this result in is_same< int , int > 
    // STATIC_ASSERT( std::is_same< RemoveModifiers<TBufferTypeFront>::type, typename RemoveModifiers<TBufferTypeFront>::type>::result )

public:

    template <typename T>
    struct MyRefTypes {
        typedef T Org;
        typedef T* Ptr;
        typedef const T & Con;
        typedef T& Ref;
        typedef const T& CRef;
        static inline Ptr getUnderlyingPtr(T& v) {
            return &v;
        }
        static Ref getRef(T& v) {
            return v;
        }
    };

    //Specialization for Reference
    template <typename T>
    struct MyRefTypes<T&> {
        typedef T Org;
        typedef T* Ptr;
        typedef T & Con;
        typedef T& Ref;
        typedef const T& CRef;
        static inline Ptr getUnderlyingPtr(T& v) {
            return &v;
        }
        static inline Ref getRef(T& v) {
            return v;
        }
    };

    //Specialization for const Reference
    template <typename T>
    struct MyRefTypes<const T&> {
        typedef T Org;
        typedef T* Ptr;
        typedef const T & Con;
        typedef const T& Ref;
        typedef const T& CRef;
        static inline Ptr getUnderlyingPtr(const T& v) {
            return &const_cast<T&>(v);
        }
        static inline Ref getRef(const T& v) {
            return v;
        }
    };

    //Specialization for const
    template <typename T>
    struct MyRefTypes<const T> {
        typedef T Org;
        typedef T* Ptr;
        typedef const T & Con;
        typedef const T& Ref;
        typedef const T& CRef;
        static inline Ptr getUnderlyingPtr(const T& v) {
            return &const_cast<T&>(v);
        }
        static inline Ref getRef(const T& v) {
            return v;
        }
    };

    //Specialization for pointers
    template <typename T>
    struct MyRefTypes<T*> {
        typedef T* Ptr;
        typedef T Org;
        typedef T* Con;
        typedef T& Ref;
        typedef T* const CRef;  //! note this is a pointer....
        static inline Ptr getUnderlyingPtr(T* v) {
            return v;
        }
        static inline Ref getRef(T* v) {
            return *v;
        }
    };

    //Specialization for const pointers
    template <typename T>
    struct MyRefTypes<const T*> {
        typedef T Org;
        typedef T* Ptr;
        typedef const T* Con;
        typedef const T& Ref;
        typedef const T* const CRef; //! note this is a pointer....
        static inline Ptr getUnderlyingPtr(const T* v) {
            return const_cast<T*>(v);
        }
        static inline Ref getRef(const T* v) {
            return *v;
        }
    };


    typedef typename MyRefTypes<TBufferTypeFront>::Ref TBufferTypeFrontRef;
    typedef typename MyRefTypes<TBufferTypeFront>::CRef TBufferTypeFrontCRef;
    typedef typename MyRefTypes<TBufferTypeFront>::Con TBufferTypeFrontCon;
    typedef typename MyRefTypes<TBufferTypeFront>::Org TBufferTypeFrontOrg;
    typedef typename MyRefTypes<TBufferTypeFront>::Ptr TBufferTypeFrontPtr;

    typedef typename MyRefTypes<TBufferTypeBack >::Ref TBufferTypeBackRef;
    typedef typename MyRefTypes<TBufferTypeBack >::CRef TBufferTypeBackCRef;
    typedef typename MyRefTypes<TBufferTypeBack >::Con TBufferTypeBackCon;
    typedef typename MyRefTypes<TBufferTypeBack >::Org TBufferTypeBackOrg;
    typedef typename MyRefTypes<TBufferTypeBack >::Ptr TBufferTypeBackPtr;

    explicit FrontBackBuffer(
                             TBufferTypeFrontCon  front,
                             TBufferTypeBackCon   back):
    m_Front(front),
    m_Back(back)
    {
        m_pBack = MyRefTypes<TBufferTypeBack>::getUnderlyingPtr(m_Back);
        m_pFront = MyRefTypes<TBufferTypeFront>::getUnderlyingPtr(m_Front);

    };


    ~FrontBackBuffer()
    {};

    TBufferTypeFrontRef getFront() {
        return *m_pFront;
    }
    TBufferTypeBackRef getBack() {
        return *m_pBack;
    }

    void swap(){
        TBufferTypeFrontPtr temp = m_pFront;
        m_pFront = m_pBack;
        m_pBack = temp;
    }

private:



    TBufferTypeFrontPtr m_pFront;       ///< The pointer to front buffer
    TBufferTypeBackPtr  m_pBack;         ///< The pointer to back buffer

    TBufferTypeFront m_Front;       ///< The front buffer
    TBufferTypeBack m_Back;         ///< The back buffer

};

我们现在可以这样使用它了:

int main() {
        int front=10;
    int back=3;
    FrontBackBuffer< const int*, int & > buf1(&front, back);
    buf1.getBack() = 4; // change from 3 to 4
    // buf.getFront() = 5; NO! is const!
    buf1.swap();
        std::cout << buf1.getFront() << buf1.getBack() << std::endl;
    //NOW getBack() and getFront() should return  4 and 10!

        front = 1;
        back= -1;
    FrontBackBuffer<int &, int > buf2(front, back);
    buf2.getBack() = 2; 
    buf2.getFront() = 3; 

    buf2.swap();   
    //NOW getBack() and getFront() should return  2 and 3!
    std::cout << buf2.getFront() << buf2.getBack() << std::endl;

        front = 1;
        back= -1;
    FrontBackBuffer<int, const int &> buf3(front, back);
    //buf3.getBack() = 2; // IS CONST!!
    buf3.getFront() = 3; 

    buf3.swap();   
    //NOW getBack() and getFront() should return  -1 and 3!
    std::cout << buf3.getFront() << buf3.getBack() << std::endl;

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-03-10
    • 1970-01-01
    • 1970-01-01
    • 2012-06-08
    • 1970-01-01
    • 2015-04-22
    • 1970-01-01
    • 2022-11-11
    相关资源
    最近更新 更多