提问人:dde 提问时间:11/15/2023 更新时间:11/15/2023 访问量:69
如何根据枚举类参数定义模板函数签名?
How to define template function signature based on enum class parameter?
问:
是否可以声明一个模板函数,使该函数的参数类型依赖于枚举类模板参数?
用例大致如下。应用程序维护不同类的实体的集合,以及这些实体之间的映射。映射编码为结构成员,如下所示:
#include<unordered_set>
using std::unordered_set;
struct Entity1;
struct Entity2;
struct Entity {
};
struct Entity1 : public Entity {
Entity1* m_parent; // source of first mapping
Entity2* m_owner; // source of first mapping
unordered_set<Entity1*> m_children; // destination of first mapping
};
struct Entity2 : public Entity {
unordered_set<Entity1*> m_elements; // destination of second mapping
};
为了对映射进行一些通用过程的编码,我希望能够识别映射的源和目标的类型。
enum class Mapping { M1, M2 };
// the following is illegal
template <Mapping r> Sig {
typename Dom;
typename Ran;
};
using Sig.Dom<Mapping::M1> = Entity1;
using Sig.Ran<Mapping::M1> = Entity1;
using Sig.Dom<Mapping::M2> = Entity1;
using Sig.Ran<Mapping::M2> = Entity2;
这是我希望能够实例化的通用过程示例。
template <Mapping r>
void link(Sig.Dom<r>* obj1, Sig.Ran<r>* obj2);
template<>
void link<Mapping::M1>(Entity1* obj1, Entity1* obj2) {
if (obj1->m_parent != nullptr) {
obj1->m_parent->m_children.erase(obj1);
}
obj1.m_parent = obj2;
if (obj1->m_parent != nullptr) {
obj1->m_parent->m_children.insert(obj1);
}
}
template<>
void link<Mapping::M2>(Entity1* obj1, Entity2* obj2) {
if (obj1->m_owner != nullptr) {
obj1->m_owner->m_elements.erase(obj1);
}
obj1.m_owner = obj2;
if (obj1->m_owner != nullptr) {
obj1->m_owner->m_elements.insert(obj1);
}
}
有没有办法在 C++ 中实现这一点?
答:
1赞
YSC
11/15/2023
#1
给你:
template <Mapping r>
struct LinkParameters
{};
template<>
struct LinkParameters<Mapping::M1>
{
using First = Entity1*;
using Second = Entity1*;
};
template<>
struct LinkParameters<Mapping::M2>
{
using First = Entity1*;
using Second = Entity2*;
};
template <Mapping r>
void link(typename LinkParameters<r>::First obj1, typename LinkParameters<r>::Second obj2)
{
if constexpr (r == Mapping::M1) {
if (obj1->m_parent != nullptr) {
obj1->m_parent->m_children.erase(obj1);
}
obj1.m_parent = obj2;
if (obj1->m_parent != nullptr) {
obj1->m_parent->m_children.insert(obj1);
}
} else {
if (obj1->m_owner != nullptr) {
obj1->m_owner->m_elements.erase(obj1);
}
obj1.m_owner = obj2;
if (obj1->m_owner != nullptr) {
obj1->m_owner->m_elements.insert(obj1);
}
}
}
这个想法是,要尽可能多地明确地对特质进行专门化。LinkParameters
link
对于 的定义,我决定使用解决方案来演示另一种方法。你只能决定什么是最好的,所有的东西大多是兼容的,所以要试验和选择。link()
constexpr if
作为替代方法,可以是使用常用惯用语(全局定义 + 显式专用化)定义的可调用类型。由于它是一种类型,因此可以包含或嵌套该特征以进行更多封装。此解决方案保留为练习。link
LinkParameters
评论
0赞
dde
11/15/2023
谢谢,这正是所需要的。请注意,代码摘录的开头缺少一行:。template <Mapping r>
0赞
YSC
11/15/2023
确实^^固定的
评论