扩展可变参数模板模板参数以用于例如std::variant<T...>
Expand variadic template template parameters for use in e.g. std::variant<T...>
这将是一个难以破解的难题。我什至不知道这是否可能。
我的目标是创建一个接收函数,该函数侦听多个队列并将通过特定队列(首先响应)接收的对象粘贴到 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() {}
很明显,这甚至没有远程编译,只是我想表明意图。队列当然也只是一个存根。 Afaik 你甚至不能通过名称 (T
) 获取模板模板参数,这是非常不幸的。有没有比我聪明的人已经想出如何解决这个问题了?
注:
到目前为止,我的做法是通过非模板 base_struct 进行动态调度。然而,这个解决方案丢失了类型信息,我的计划是在 multireceive
的调用点通过 std::visit 分派变体。这将是一个非常巧妙的解决方案,可以直接从队列事件中分派。
由于您所有的队列都使用相同的模板 (queue<...>
),因此您不需要模板模板参数(其中,顺便说一句,嵌套参数的名称 (T
在你的情况下)被忽略)。您只需要一个类型包:typename ...T
.
我也摆脱了变体数组,而是选择直接迭代参数,在折叠表达式中使用 lambda。尽管这使得提取 return 值变得更加困难,所以我将其放入 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);
}
这将是一个难以破解的难题。我什至不知道这是否可能。
我的目标是创建一个接收函数,该函数侦听多个队列并将通过特定队列(首先响应)接收的对象粘贴到 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() {}
很明显,这甚至没有远程编译,只是我想表明意图。队列当然也只是一个存根。 Afaik 你甚至不能通过名称 (T
) 获取模板模板参数,这是非常不幸的。有没有比我聪明的人已经想出如何解决这个问题了?
注:
到目前为止,我的做法是通过非模板 base_struct 进行动态调度。然而,这个解决方案丢失了类型信息,我的计划是在 multireceive
的调用点通过 std::visit 分派变体。这将是一个非常巧妙的解决方案,可以直接从队列事件中分派。
由于您所有的队列都使用相同的模板 (queue<...>
),因此您不需要模板模板参数(其中,顺便说一句,嵌套参数的名称 (T
在你的情况下)被忽略)。您只需要一个类型包:typename ...T
.
我也摆脱了变体数组,而是选择直接迭代参数,在折叠表达式中使用 lambda。尽管这使得提取 return 值变得更加困难,所以我将其放入 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);
}