扩展可变参数模板参数以在例如 std::variant<T...> 中使用

gla*_*des 1 c++ variadic-templates c++17

这将是一个很难解决的问题。我什至不知道这是否可能。

我的目标是创建一个接收函数,该函数侦听多个队列并将通过特定队列(首先响应)接收的对象粘贴到 return 语句中的堆栈。这将通过 std::variant 完成。棘手的部分是类型:每个队列都保存不同的类型,因此 multireceive() 内部的变体需要根据用于作为可变参数传递到其中的队列的模板参数来构造。当然,最终队列对象只能作为引用传递。

到目前为止,这是我的方法,但是您可以看到我非常不清楚如何编写包扩展。我想我可能正在突破 C++ 的极限:

#include <array>
#include <variant>

template <typename T>
struct queue
{
    T queue_[100];
    
    T receive()
    {
        return queue_[0];
    }
};

// doesn't compile!
template <template <typename... T> class Q>
std::variant<T...> multireceive(Q<T>&... Arg)
{
    std::array<std::variant<Arg*...>, sizeof...(T)> queues = { (&Arg )... };

    do {
        for (size_t i=0; i < sizeof...(T); ++i) {
            if (queues[i]->receive()) {
                return *queues[i];
            }
        }
    } while(1) // busy wait
}

int main() {}
Run Code Online (Sandbox Code Playgroud)

显然,这甚至不能远程编译,这只是我试图表明意图。队列当然也只是一个存根。据我所知,您甚至无法通过名称(T)获取模板模板参数,这是非常不幸的。有比我聪明的人已经知道如何解决这个问题了吗?

笔记

到目前为止,我的做法是通过非模板化的 base_struct 进行动态调度。然而,这个解决方案丢失了类型信息,我的计划是通过 std::visit 在 的调用站点调度变体multireceive。这将是一个非常简洁的解决方案,可以直接从队列事件调度。

Hol*_*Cat 5

由于所有队列都使用相同的模板 ( queue<...>),因此您不需要模板模板参数(顺便说一下,其中嵌套参数的名称(T在您的情况下)将被忽略)。您只需要一个类型包:typename ...T

我还摆脱了变体数组,而是选择直接迭代参数,在折叠表达式中使用 lambda。尽管这使得提取返回值变得更加困难,所以我将其放入optional

#include <array>
#include <optional>
#include <variant>

template <typename T>
struct queue
{
    T queue_[100];
    
    T receive()
    {
        return queue_[0];
    }
};

template <typename ...P>
std::variant<P...> multireceive(queue<P> &... args)
{
    std::optional<std::variant<P...>> ret;

    while (true)
    {
        // For each `args...`:
        ([&]{
            // Do something with `args` (the current queue).
            if (args.receive())
            {
                ret.emplace(args.queue_[0]);
                return true; // Stop looping over queues.
            }
            return false;
        }() || ...);

        if (ret)
            break;
    }

    return *ret;
}

int main()
{
    queue<int> a;
    queue<float> b;

    std::variant<int, float> var = multireceive(a, b);
}
Run Code Online (Sandbox Code Playgroud)