映射可变参数模板参数
Map Variadic Template Arguments
在下面的代码中,我想找到一种更通用的方式来调用GenericPublish__Advertise((,它需要一个可变参数模板列表。我能做些什么来改进它?
我想将主题映射到特定类型的发布者:
- 主题[0] -> 出版商[0]
- 主题[1] -> 出版商[1]
- 等等
虽然代码工作正常,但我需要手动编写 GenericPublish__Advertise(( 的模板化版本并手动将主题 [i] 映射到发布者。我想以某种方式概括 GenericPublish__Advertise(( 的实现。
提前非常感谢。
法典:
#include <iostream>
#include <memory>
#include <typeinfo>
#include <vector>
class AdvertiseOptionsBase {
public:
virtual const std::type_info &GetType() = 0;
};
template <typename TSend>
class AdvertiseOptions : public AdvertiseOptionsBase {
public:
AdvertiseOptions(TSend opt) : opt_(opt) {}
const std::type_info &GetType() { return typeid(opt_); }
private:
TSend opt_;
};
class Publisher {
public:
Publisher(const std::string &topic) : topic_(topic) {}
const std::string &GetTopic() const { return topic_; }
template <typename TSend>
void SetOptions(const AdvertiseOptions<TSend> &opt) {
options_ = std::make_unique<AdvertiseOptions<TSend>>(opt);
}
const std::unique_ptr<AdvertiseOptionsBase> &GetOptions() const {
return options_;
}
private:
std::string topic_;
std::unique_ptr<AdvertiseOptionsBase> options_;
};
class Node {
public:
template <typename TSend>
Publisher advertise(std::string topic) {
Publisher publisher(topic);
TSend option;
AdvertiseOptions<TSend> options(option);
publisher.SetOptions<TSend>(options);
return publisher;
}
};
template <typename TSend1, typename TSend2>
void GenericPublish__Advertise(Node &node, std::vector<Publisher> &publishers,
const std::vector<std::string> &topics) {
publishers.push_back(node.advertise<TSend1>(topics.at(0)));
publishers.push_back(node.advertise<TSend2>(topics.at(1)));
}
template <typename TSend1, typename TSend2, typename TSend3>
void GenericPublish__Advertise(Node &node, std::vector<Publisher> &publishers,
const std::vector<std::string> &topics) {
publishers.push_back(node.advertise<TSend1>(topics.at(0)));
publishers.push_back(node.advertise<TSend2>(topics.at(1)));
publishers.push_back(node.advertise<TSend3>(topics.at(2)));
}
template <typename... TSend>
class GenericPublish {
public:
GenericPublish(const std::vector<std::string> &topics) {
GenericPublish__Advertise<TSend...>(node_, publishers_, topics);
}
void PrintInfo() {
for (const auto &publisher : publishers_) {
std::cout << publisher.GetTopic() << " -----> "
<< (publisher.GetOptions()->GetType()).name() << std::endl;
}
}
protected:
Node node_;
std::vector<Publisher> publishers_;
private:
};
int main() {
std::vector<std::string> topics({"topic_int", "topic_double"});
GenericPublish<int, double> o(topics);
o.PrintInfo();
return 0;
}
这里的典型方法是使用索引序列技巧。获取类型的参数包,构造相同大小的索引序列,然后循环访问两者:
template <typename... TSends> // <== pack of types
void GenericPublishAdvertise(Node &node, std::vector<Publisher> &publishers,
const std::vector<std::string> &topics)
{
GenericPublishAdvertiseImpl<TSends...>(node, publishers, topics,
std::index_sequence_for<TSends...>()); // <== index sequence creation
}
使用单独的实现执行以下操作:
template <typename... TSends, size_t... Is>
void GenericPublishAdvertiseImpl(Node &node, std::vector<Publisher> &publishers,
const std::vector<std::string> &topics, std::index_sequence<Is...> )
{
// since this is C++14
using swallow = int[];
(void)swallow{0,
(void(publishers.push_back(node.advertise<TSends>(topics.at(Is)))), 0)...
};
// in C++17, that's just
(publishers.push_back(node.advertise<TSends>(topics.at(Is))), ...);
}
有关该模式的说明,请参阅此答案。
请注意,使用GenericPublish__Advertise
是 UB:保留带有双下划线的名称。
template <class ... TSends, std::size_t ... Is>
GenericPublish__Advertise_impl(Node &node, std::vector<Publisher> &publishers,
const std::vector<std::string>& topics, std::index_sequence<Is...>)
{
(void)int x[] = {(publishers.push_back(node.advertise<TSends>(topics.at(Is))), 0)...};
}
template <class ... TSends>
GenericPublish__Advertise((Node &node, std::vector<Publisher> &publishers,
const std::vector<std::string>& topics)
{
GenericPublish__Advertise_impl(node, publishers, topics, std::index_sequence_for<TSends...>{});
}
这里有两个技巧,当你想对可变参数包进行某种索引时,它们是非常标准的。第一件事是委托给一个实现函数,传递所有参数,以及这个std::index_sequence
类型。这允许实现函数推导出一个整数包,该整数将编号为 0 到 N-1,一个大小为 N 的包。其次,初始化一个未使用的虚拟数组,并使用逗号运算符丢弃您正在执行的任何操作的返回(或缺少返回(,并简单地返回 0。
相关文章:
- 在不传递参数数量且只有3个点的情况下,如何使用变差函数
- 如何使用可变参数模板强制转换每个变体类型
- 关于如何在具有单个参数的变体构造中选择替代方案?
- 调用参数排列不变函数 f(i++, i++)
- 参数归纳与标准::变体
- 模板化回调参数的逆变,如 C# 中的逆变
- 如何在没有参数包的情况下编写变差函数
- 通过具有嵌套类的工厂类获取多个变异类模板参数包
- 获取模板参数的成员变量值列表
- 保留短 lambda 用作函数的中间参数,使用 clang 格式保持不变
- 如何定义变体<x,y,z>提取模板参数的子类型
- 正确对齐内存模板,参数顺序不变
- 递归中不同参数类型的变元模板函数
- 通过函数指针传递给变差函数的参数会更改其值
- 提升预定义为带有参数的全局 lambda 的变体访问者
- 使用可变参数模板参数提升变体访问者
- boost ::变体 - 为什么模板参数比const字符串参数具有更高的优先级
- 将变参数包中的值加载到临时数组中
- 使用额外参数提升变体访客
- 正在将动态数组元素解析为参数?(变音符)