基于C++可变参数模板实现同基类子类测试方法的技术问询
Got it, let's work through how to implement your tester_queues template function properly. First, let's break down the issues in your original code, then fix them step by step.
Key Issues in the Original Code
- Missing argument for
push: Thetest_push_popfunction callsaQueueP->push()without any parameters, but yourIQueue<T>::pushrequires aconst T&input. We need to pass a valid test value here. - Invalid vector type: You can't create a
std::vector<IQueue*>becauseIQueueis a template class—IQueue<int>andIQueue<char>are completely distinct types with no shared non-template base class. Storing pointers to differentIQueue<T>specializations in the same vector isn't allowed. - Incorrect parameter pack unpacking: Each queue type in the parameter pack has its own underlying
Ttype, so we need to handle each type individually instead of trying to group them into a single vector.
Fixed Implementation
First, let's add a type alias to IQueue to easily access its template parameter from subclasses:
#include <iostream> template<class T> class IQueue { protected: T Data[10]; public: using value_type = T; // Expose the underlying data type for easy access virtual const T pop() = 0; virtual void push(const T&) = 0; };
Next, fix the test_push_pop function to pass a valid argument to push:
template<class T> void test_push_pop(IQueue<T>* aQueueP) { aQueueP->push(T{}); // Use a default-constructed T as the test input aQueueP->pop(); }
Now, implement tester_queues using C++17 fold expressions (the cleanest approach) to unpack the parameter pack and test each queue type:
template<class... QueueTypes> void tester_queues() { // Fold expression to iterate over every type in the parameter pack ( [&](){ QueueType queue; // Create an instance of the current queue type // Cast to the correct IQueue<T> pointer and run tests test_push_pop(static_cast<IQueue<typename QueueType::value_type>*>(&queue)); }(), ... ); }
If you're stuck with C11/C14, use recursive template expansion instead:
// Base case: stop recursion when no types are left void tester_queues() {} // Recursive case: test the first type, then recurse with remaining types template<class QueueType, class... Rest> void tester_queues() { QueueType queue; test_push_pop(static_cast<IQueue<typename QueueType::value_type>*>(&queue)); tester_queues<Rest...>(); }
Full Working Code
Don't forget to add the public specifier to your queue subclass methods (they were missing in the original code, making the overrides inaccessible):
#include <iostream> template<class T> class IQueue { protected: T Data[10]; public: using value_type = T; virtual const T pop() = 0; virtual void push(const T&) = 0; }; template<class T> class QueueA : public IQueue<T> { public: const T pop() final { std::cout << "pop queue A" << std::endl; return T{}; } void push(const T& aItemRef) final { std::cout << "PUSH queue A" << std::endl; } }; template<class T> class QueueB : public IQueue<T> { public: const T pop() final { std::cout << "pop queue B" << std::endl; return T{}; } void push(const T& aItemRef) final { std::cout << "PUSH queue B" << std::endl; } }; template<class T> void test_push_pop(IQueue<T>* aQueueP) { aQueueP->push(T{}); aQueueP->pop(); } template<class... QueueTypes> void tester_queues() { ( [&](){ QueueType queue; test_push_pop(static_cast<IQueue<typename QueueType::value_type>*>(&queue)); }(), ... ); } int main() { tester_queues<QueueA<int>, QueueB<char>>(); return 0; }
Output
When you run this code, you'll see:
PUSH queue A pop queue A PUSH queue B pop queue B
Each queue type is instantiated and tested individually, just like you wanted.
内容的提问来源于stack exchange,提问作者Bebe Carabina

