c++ 如何定义基于枚举类参数的模板函数签名?

kh212irz  于 12个月前  发布在  其他
关注(0)|答案(1)|浏览(97)

是否可以声明一个模板函数,使函数的参数类型依赖于枚举类模板参数?
用例大致如下。应用程序维护不同类的实体集合,以及这些实体之间的Map。Map被编码为结构成员,如下所示:

#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
};

字符串
为了编写一些关于Map的通用过程,我希望能够识别Map的源和目的地的类型。

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++中实现这一点?

zf9nrax1

zf9nrax11#

给你:

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);
        }
    }
}

字符串
Full program demo
我们的想法是让LinkParameters的显式特化与link的可能特化一样多。
对于link()的定义,我决定使用constexpr if解决方案来演示另一种方法。你只能决定哪种是最好的,所有的都是兼容的,所以实验和选择。
作为替代方案,link可以是一个用常用的习惯用法(全局定义+显式专门化)定义的可调用类型。因为它是一个类型,它可以包含或嵌套LinkParameters trait以进行更多的封装。这个解决方案作为练习。

相关问题