参数“队列内容”阴影模板参数模板类队列类型

Parameter ‘QueueContents’ shadows template parameter template class QueueType

本文关键字:参数 队列 类型 阴影 队列内容      更新时间:2023-10-16

此代码从以下链接引用

我真的无法弄清楚这个错误并第一次看到它

整个代码

#include <boost/thread/thread.hpp>
#include <boost/lockfree/queue.hpp>
#include <iostream>
#include <queue>
#include <boost/atomic.hpp>
template<typename QueueContents, template<typename QueueContents> class QueueType>
class WorkerThread
{
public:
    WorkerThread(QueueType<QueueContents> &Queue, int NoOfIt, int Delay)
        : m_Queue(Queue)   // queue shared with consumer
        , m_Delay(Delay)   // delay for simulating heavy work
        , m_NoOfIt(NoOfIt) // number of work items to produce
    {}
    void Start() // start work
    {
        m_Thread = boost::thread(&WorkerThread::Work, this);
    }
    void Stop() // interrupt work
    {
        m_Thread.interrupt();
    }
    virtual void Work() = 0;
    void WaitUntilFinished()
    {
        m_Thread.join();
    }
protected:
    int m_NoOfIt;
    int m_Delay;
    QueueType<QueueContents> &m_Queue;
private:
    boost::thread m_Thread;
};
template<typename QueueContents, template<typename QueueContents> class QueueType>
class Producer : public WorkerThread<QueueContents, QueueType>
{
public:
    Producer(QueueType<QueueContents> &Queue, int NoOfIt, int Delay)
        : WorkerThread<QueueContents, QueueType>(Queue, NoOfIt, Delay)
    {}
    void Work()
    {
        for (QueueContents i=0; i < this->m_NoOfIt; ++i)
        {
            // send numbers 0 to 999 into the queue
            boost::this_thread::sleep(boost::posix_time::milliseconds(this->m_Delay));
            std::ostringstream msg;
            msg << "[PRODUCER] Produced value " << i << std::endl;
            std::cout << msg.str();
            this->m_Queue.Push(i);
        }
    }
};
// New BSD License
class ResetableEvent
{
    bool m_EventStatus;
    bool m_AutoResetEvent;
    boost::condition_variable m_Signal;
    boost::mutex m_Mutex;
public:
    explicit ResetableEvent(bool _auto_reset = false)
        : m_EventStatus(false)
        , m_AutoResetEvent(_auto_reset)
    {}
    void wait() // wait for event
    {
        boost::unique_lock<boost::mutex> lock(m_Mutex);
        if (m_EventStatus)
        {
            if (m_AutoResetEvent)
                m_EventStatus = false;
            return;
        }
        do
        {
            m_Signal.wait(lock);
        } while(!m_EventStatus);
        if (m_AutoResetEvent)
            m_EventStatus = false;
    }
    void set() // this notifies threads waiting for this event
               // and makes sure that other threads about to wait
               // can immediately proceed
    {
        boost::lock_guard<boost::mutex> lock(m_Mutex);
        m_EventStatus = true;
        m_Signal.notify_one();
    }
    void reset() // reset event: threads who will wait for this
                 // event will be blocked
    {
        boost::lock_guard<boost::mutex> lock(m_Mutex);
        m_EventStatus = false;
    }
};

// Queue class that can be used in multithreading context
template <typename T>
class BoundedThreadSafeQueueSignalWorkloadDone
{
private:
    std::queue<T> m_queue;                    // Use STL queue to store data
    boost::mutex m_mutex;                     // The mutex to synchronise on
    boost::condition_variable m_QueueHasData; // The condition to wait for if queue is empty
    boost::condition_variable m_QueueHasRoom; // The condition to wait for if queue is full
    ResetableEvent m_ProcessingDone;   // The conditon to wait for if queue is empty
                                       // and workload is fully processed
    unsigned int m_Size;               // max queue size
public:
    BoundedThreadSafeQueueSignalWorkloadDone(unsigned int Size)
        : m_Size(Size)
    {
        m_ProcessingDone.set();
    }
    bool Empty()
    {
        // Acquire lock on the queue
        boost::unique_lock<boost::mutex> lock(m_mutex);
        return m_queue.empty();
    }
    bool Full()
    {
        // Acquire lock on the queue
        boost::unique_lock<boost::mutex> lock(m_mutex);
        return m_queue.size() >= m_Size;
    }
    // Push new data on the queue and notify other threads
    // waiting for data in this queue
    bool TryPush(const T &data)
    {
        // Acquire lock on the queue
        boost::unique_lock<boost::mutex> lock(m_mutex);
        // Indicate that workload processing is busy
        // Fail if queue full
        if (m_queue.size() >= m_Size) return false;
        // Indicate that workload is being processed
        m_ProcessingDone.reset();
        // Add the data to the queue
        m_queue.push(data);
        // Notify others that data is ready
        m_QueueHasData.notify_one();
        return true;
    } // Lock is automatically released here
    // Try to push data in queue
    // Wait until room in queue
    void Push(const T &data)
    {
        // Acquire lock on the queue
        boost::unique_lock<boost::mutex> lock(m_mutex);
        // While queue is full, wait
        // warning: do not replace m_queue.size() == m_Size with Full():
        // it will deadlock due to trying to acquire the same m_mutex
        // Push has already acquired
        while (m_queue.size() >= m_Size) m_QueueHasRoom.wait(lock);
        // Indicate that workload is being processed
        m_ProcessingDone.reset();
        // Now push the data
        m_queue.push(data);
        // And warn threads that are waiting for data
        m_QueueHasData.notify_one();
    }
    // Get data from the queue.
    // Return false if no data available
    bool TryPop(T &result)
    {
        // Acquire lock on the queue
        boost::unique_lock<boost::mutex> lock(m_mutex);
        // When there is no data, return false
        if (m_queue.size() == 0) return false;
        // Otherwise return the data
        // Retrieve the data from the queue
        result=m_queue.front(); m_queue.pop();
        // Warn threads who are waiting to push data
        m_QueueHasRoom.notify_one();
        return true;
        // Lock is automatically released here
    }
    // Get data from the queue.
    // Wait for data if not available
    void WaitAndPop(T &result)
    {
        // Acquire lock on the queue
        boost::unique_lock<boost::mutex> lock(m_mutex);
        // When there is no data, wait till someone fills it.
        // Lock is automatically released in the wait and obtained
        // again after the wait
        while (m_queue.size() == 0) m_QueueHasData.wait(lock);
        // Retrieve the data from the queue
        result=m_queue.front(); m_queue.pop();
        // Warn threads who are waiting to push data
        m_QueueHasRoom.notify_one();
     } // Lock is automatically released here
    void ProcessingFinished()
    {
        // Acquire lock on the queue
        boost::unique_lock<boost::mutex> lock(m_mutex);
        // If no new work scheduled,
        // we can signal the queue as completely idle
        if (m_queue.empty())
            m_ProcessingDone.set();
        else
            std::cout << "[QUEUE] ProcessingFinished but queue not empty. ProcessingDone flag remains low." << std::endl;
    }
    void WaitUntilCompletelyIdle()
    {
        std::cout << "[QUEUE] Wait until idle" << std::endl;
        m_ProcessingDone.wait();
        std::cout << "[QUEUE] Consumer is completely idle" << std::endl;
    }
};
template<typename QueueContents, template<typename QueueContents> class QueueType>
class Producer : public WorkerThread<QueueContents, QueueType>
{
public:
    Producer(QueueType<QueueContents> &Queue, int NoOfIt, int Delay)
        : WorkerThread<QueueContents, QueueType>(Queue, NoOfIt, Delay)
    {}
    void Work()
    {
        for (QueueContents i=0; i< this->m_NoOfIt; ++i)
        {
            // send numbers 0 to 999 into the queue
            boost::this_thread::sleep(boost::posix_time::milliseconds(this->m_Delay));
            std::ostringstream msg;
            msg << "[PRODUCER] Produced value " << i << std::endl;
            std::cout << msg.str();
            this->m_Queue.Push(i);
        }
    }
};
template<typename QueueContents, template<typename QueueContents> class QueueType>
class Consumer : public WorkerThread<QueueContents, QueueType>
{
public:
    Consumer(QueueType<QueueContents> &Queue, int NoOfIt, int Delay)
        : WorkerThread<QueueContents, QueueType>(Queue, NoOfIt, Delay)
    {}
    void Work()
    {
        for (QueueContents i=0; i< this->m_NoOfIt; ++i)
        {
            // read data from the queue,
            // waiting until data available
            int num = -1;
            this->m_Queue.WaitAndPop(num);
            std::ostringstream msg;
            msg << "[CONSUMER] Consumed value " << num << std::endl;
            std::cout << msg.str();
            boost::this_thread::sleep(boost::posix_time::milliseconds(this->m_Delay)); // work hard
            this->m_Queue.ProcessingFinished(); // tell the queue we're done working hard
            std::ostringstream msg2;
            msg2 << "[CONSUMER] Consumption of value " << num << " completely handled." << std::endl;
            std::cout << msg2.str();
        }
    }
};
int main()
{
    std::cout << "[MAIN] About to construct queue" << std::endl;
    BoundedThreadSafeQueueSignalWorkloadDone<int> Q(3);
    std::cout << "[MAIN] About to construct producer" << std::endl;
    Producer<int, BoundedThreadSafeQueueSignalWorkloadDone> P(Q, 10, 0);
    std::cout << "[MAIN] About to construct consumer" << std::endl;
    Consumer<int, BoundedThreadSafeQueueSignalWorkloadDone> C(Q, 10, 100);
    std::cout << "[MAIN] About to start producer" << std::endl;
    P.Start();
    std::cout << "[MAIN] About to start consumer" << std::endl;
    C.Start();
    for (unsigned int i=0; i<20;++i)
    {
        C.WaitUntilCompletelyIdle();
        boost::this_thread::sleep(boost::posix_time::milliseconds(2));
    }
    std::cout << "[MAIN] Queue should be empty after all threads finished: " << Q.Empty() << std::endl;
    std::cout << "[MAIN] Waiting for producer to finish" << std::endl;
    P.WaitUntilFinished();
    std::cout << "[MAIN] Waiting for consumer to finish" << std::endl;
    C.WaitUntilFinished();
    return 0;
}

错误

main.cpp:6:43: error: declaration of template parameter
‘QueueContents’ shadows template parameter  template<typename
QueueContents, template<typename QueueContents> class QueueType>

代码是错误的,它违反了规则 [temp.local]/6,该规则不允许将模板参数名称重用于任何其他目的。

模板参数不得在其作用域(包括嵌套作用域(内重新声明。

作者可能使用了GCC 5,它没有实现规则,但从GCC 6开始,它就实现了。
现场演示

作为快速修复,只需删除模板模板参数名称。反正不用。

template<typename QueueContents, template<typename> class QueueType>
class WorkerThread
. . .