首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >(C++11)是否有办法限制特定类上模板参数的范围?

(C++11)是否有办法限制特定类上模板参数的范围?
EN

Stack Overflow用户
提问于 2020-03-28 10:32:30
回答 1查看 79关注 0票数 0

Definition_________________________问题

!!You can skip here and directly go to■ Question Summary !!

我设计了一个灵活但内存高效的类,它适用于各种情况,其中只有选择特性:链接

另外,我为每个特征提供了ID,当用户只请求类的特定特征时,就会使用它。

我编写了满足这些属性的自己的类,使用多继承 of 未命名枚举可变模板

见下文:

Triits.h

代码语言:javascript
复制
struct TriT
{
    struct Centroid
    {
        Point3D centroid;
        struct ID { enum : utin8_t { CENTROID = 1 }; }; // 0000 0001
    };

    struct Area
    {
        double area;
        struct ID { enum : utin8_t { AREA = 2 }; }; // 0000 0010
    };

    struct Perimeter
    {
        double perimeter;
        struct ID { enum : utin8_t { PERIMETER = 4 }; }; // 0000 0100
    };
    ... // More traits...
};

Triangle.h

代码语言:javascript
复制
#include "TriTraits.h"

enum class TRI_TRAIT_ID : uint8_t {}; // strong type
template<class... Traits>
struct TriangleT : Traits...
{
    struct IDs : Traits::ID...
    {
        enum : uint8_t {
            NONE = 0, // 0000 0000
            ALL = 255 // 1111 1111
        };
    };
    void ComputeTrait(TRI_TRAIT_ID _requestedIDs)
    {
        ... // Implementation will be written somehow, using bitwise & operator.
    }
};

例如,如果定义自己的三角形类型MyTri<TriT::Area, TriT::Perimeter> myTri,编译器所看到的可能如下所示:

代码语言:javascript
复制
struct MyTri
{
    double area;
    double perimeter;

    struct IDs // Since enum can't be inherited, it has 3 individual unnamed enums in it
    {
        enum : uint8_t { AREA = 2 };
        enum : uint8_t { PERIMETER = 4 };
        enum : uint8_t {
            NONE = 0,
            ALL = 255
        };
    };
} myTri;

这个自定义三角形类型将通过使用按位的调用ComputeTraits(...)来计算的一些特征,如下所示:

代码语言:javascript
复制
myTri.ComputeTraits(MyTri::IDs::AREA | MyTri::IDs::PERIMETER); // Compute area and perimeter

问题出现在这里,:假设有Rectangle.hPentagon.h**,...** NthPolygon.h,以同样的方式出现。

我希望我的每个自定义多边形类型为其ComputeTrait(...)获取一个ComputeTrait(...)参数(因此我为它使用了枚举类),以防止采用混合类型的多边形特征的愚蠢操作,例如

代码语言:javascript
复制
myTri.ComputeTraits(MyTri::IDs::AREA | MyRect::IDs::PERIMETER); // Mixed traits of a triangle and of  a rectangle.

因此,我想重载|operator,它在NthPolygon::IDs::...的每个作用域中只接受未命名的枚举

我尝试将重载的模板操作符写入( NthPolygon::IDs::...private作用域),但这失败了,因为类内操作符重载总是将第一个参数作为自身:链接

使其成为全局范围的friend也失败了,因为每个N个多边形类都会有超过一个重载的|operator

代码语言:javascript
复制
enum class N_TH_POLYGON_TRAIT_ID : uint8_t {}; // strong type
struct NthPolygon
{
    ...
    struct IDs
    {
        ...
     private:
        template<typename TRAIT_ID1, typename TRAIT_ID2>
        N_TH_POLYGON_TRAIT_ID operator|(TRAIT_ID1 _id1, TRAIT_ID2 _id2) // Error : too many operators for this operator function
        { return static_cast<N_TH_POLYGON_TRAIT_ID>(static_cast<utin8_t>(_id1) | static_cast<utin8_t>(_id2)); }

        template<typename TRAIT_ID1, typename TRAIT_ID2>
        friend N_TH_POLYGON_TRAIT_ID operator|(TRAIT_ID1 _id1, TRAIT_ID2 _id2) // Error : more than 1 operator "|" matches these operands
        { return static_cast<N_TH_POLYGON_TRAIT_ID>(static_cast<utin8_t>(_id1) | static_cast<utin8_t>(_id2)); }
    };
} myTri;
代码语言:javascript
复制

Summary_________________________问题

在下面的情况下,如何使模板重载的operator|只从特定类获取参数(未命名枚举)?

代码语言:javascript
复制
enum class STRONG_TYPE_TRI_TRAIT_ID : uint8_t {};
struct Triangle
{
    struct IDs {
        enum : utin8_t { A = 1 };
        enum : utin8_t { B = 2 };
        enum : utin8_t { C = 3 };
    };
};
template<typename TRI_TRAIT_ID1, typename TRI_TRAIT_ID2>
STRONG_TYPE_TRI_TRAIT_ID operator|(TRI_TRAIT_ID1 _id1, TRI_TRAIT_ID2 _id2)
{ return static_cast<STRONG_TYPE_TRI_TRAIT_ID>(static_cast<uint8_t>(_id1) | static_cast<uint8_t>(_id2)); }
代码语言:javascript
复制
enum class STRONG_TYPE_RECT_TRAIT_ID : uint8_t {};
struct Rectangle
{
    struct IDs {
        enum : utin8_t { A = 1 };
        enum : utin8_t { B = 2 };
        enum : utin8_t { C = 3 };
    };
};
template<typename RECT_TRAIT_ID1, typename RECT_TRAIT_ID2>
STRONG_TYPE_RECT_TRAIT_ID operator|(RECT_TRAIT_ID1 _id1, RECT_TRAIT_ID2 _id2)
{ return static_cast<STRONG_TYPE_RECT_TRAIT_ID >(static_cast<uint8_t>(_id1) | static_cast<uint8_t>(_id2)); }
代码语言:javascript
复制
int main(void)
{
    Triangle::IDs::A | Triangle::IDs::B;  // OK
    Triangle::IDs::A | Rectangle::IDs::B; // Error
    ...
    return 0;
}
EN

Stack Overflow用户

回答已采纳

发布于 2020-03-28 11:24:49

不确定它是否满足了您的要求,但您可能会这样做:

代码语言:javascript
复制
template <typename Tag>
struct TriT
{
    enum class ID_t : uint8_t {};
    friend ID_t operator | (ID_t lhs, ID_t rhs)
    {
        return ID_t(uint8_t(lhs) | uint8_t(rhs));
    }

    struct Centroid
    {
        Point3D centroid;
        struct ID { static const ID_t CENTROID = ID_t(1); }; // 0000 0001
    };

    struct Area
    {
        double area;
        struct ID { static const ID_t AREA = ID_t(2); }; // 0000 0010
    };

    struct Perimeter
    {
        double perimeter;
        struct ID { static const ID_t PERIMETER = ID_t(4); }; // 0000 0100
    };

};

template<typename TRI_TRAIT_ID, class... Traits>
struct TriangleT : Traits...
{
    struct IDs : Traits::ID...
    {
        static constexpr TRI_TRAIT_ID NONE = TRI_TRAIT_ID(0);
        static constexpr TRI_TRAIT_ID ALL = TRI_TRAIT_ID(255);
    };
    void ComputeTrait(TRI_TRAIT_ID _requestedIDs)
    {
        // Implementation will be written somehow, using bitwise & operator.
    }
};

与用法:

代码语言:javascript
复制
struct TriTag;
struct RectTag;

using MyTri = TriangleT<TriT<TriTag>::ID_t, TriT<TriTag>::Area, TriT<TriTag>::Perimeter>;
using MyRect = RectT<TriT<RectTag>::ID_t, TriT<RectTag>::Area, TriT<RectTag>::Perimeter>;

int main()
{
    MyTri myTri;

    myTri.ComputeTrait(MyTri::IDs::AREA | MyTri::IDs::PERIMETER);
    //myTri.ComputeTrait(MyTri::IDs::AREA | MyRect::IDs::PERIMETER); // error as expected
}

演示

票数 1
EN
查看全部 1 条回答
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/60899980

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档