c++ 可变参数模板,相同基数的参数后代 class

c++ variadic templates, arguments descendants of same base class

考虑以下基本接口及其两个具体实现。我想用 1 个模板方法测试这些方法,参数是要测试的类型。所有子类型(QueueA、QueueB)都继承自 IQueue。我怎样才能实现模板方法 tester_queues 的实现?通过传入 类 实例的 std::vector 可以实现类似的功能,并且会更容易。我只是好奇是否可以实现方法 tester_queues 中描述的内容。

template<class T>
class IQueue
{
protected:
    T Data[10];
public:
    virtual const T pop()          = 0;
    virtual void     push(const T&) = 0;
};

template<class T>
class QueueA : public IQueue<T>
{
    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>
{
    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();
    aQueueP->pop();
};


template<class ... ARGS>
void tester_queues()
{
    // unpack ARGS
    // construct objects of each type into in a vector
    // std::vector<IQueue*> vec = { ARGS... };
    // then execute test_push_pop for each
    // std::for_each(vec.begin(), vec.end(), [](IQueue* itemP) {
    //      test_push_pop(itemP);
    // });
};


int main()
{
    tester_queues<QueueA<int>,
                  QueueB<char>>();
    return 0;
}

如果你真的只想指定队列类型作为模板参数,那么你可以使用类似这样的东西让tester_queues()在内部构造这些类型的实例以进行测试:

#include <iostream>

template<class T>
class IQueue
{
protected:
    T Data[10];
public:
    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... Ts>
struct Tester;

template <class T, class... Ts>
struct Tester<T, Ts...>
{
    template<class U>
    static void test_push_pop(IQueue<U>&& aQueueP)
    {
        aQueueP.push(U{});
        aQueueP.pop();
    }

    static void test_push_pops()
    {
        test_push_pop(T{});
        Tester<Ts...>::test_push_pops();
    }
};

template<>
struct Tester<>
{
    static void test_push_pops() {}
};

template<class... Ts>
void tester_queues()
{
    Tester<Ts...>::test_push_pops();
};

int main()
{
    tester_queues< QueueA<int>, QueueB<char> >();
    return 0;
}

Live Demo

或者,您可以构建自己的所需类型的对象,然后将它们作为输入参数传递给 tester_queues(),例如:

#include <iostream>
#include <utility>

template<class T>
class IQueue
{
protected:
    T Data[10];
public:
    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();
}

void test_push_pops()
{
}

template<class T, class... Ts>
void test_push_pops(T&& aQueueP, Ts&&... aQueuePs)
{
    test_push_pop(std::forward<T>(aQueueP));
    test_push_pops(aQueuePs...);
};

template<class... Ts>
void tester_queues(Ts&&... args)
{
    test_push_pops(args...);
};

int main()
{
    tester_queues( QueueA<int>{}, QueueB<char>{} );
    return 0;
}

Live Demo