当前位置: 首页 > 知识库问答 >
问题:

(C 11)是否有任何方法限制特定类上模板参数的范围?

古明煦
2023-03-14

■ 问题定义_________________________

<代码>!!您可以跳过这里,直接进入■问题总结!!

我设计了一个灵活但记忆效率高的类,它适合各种情况,其中只有选择性特征:链接

另外,我为每个特性提供了ID,当用户只想请求类的特定特性时,可以使用该ID。

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

见下文:

▼TriTraits. h

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

▼ 三角形

#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

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;

这个自定义三角形类型将通过调用< code>ComputeTraits(...)与按位< code > |运算符,如下所示:

myTri.ComputeTraits(MyTri::IDs::AREA | MyTri::IDs::PERIMETER); // Compute area and perimeter

问题就出在这里:假设有< code>Rectangle.h和< code>Pentagon.h,...< code>NthPolygon.h,以同样的方式。

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

myTri.ComputeTraits(MyTri::IDs::AREA | MyRect::IDs::PERIMETER); // Mixed traits of a triangle and of  a rectangle.

所以我想重载< code>|operator,它只接受< code>NthPolygon::IDs:的每个作用域中的未命名枚举...。

我尝试在 NthPolygon::IDs::...私有范围内编写重载模板运算符,但这失败了,因为类内运算符重载始终将第一个参数作为自身:link

使其成为全局作用域的< code >友元也失败了,因为对于每第N个面类,将有不止1个重载的< code>|operator。

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;

■问题摘要_________________________

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

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)); }
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)); }
int main(void)
{
    Triangle::IDs::A | Triangle::IDs::B;  // OK
    Triangle::IDs::A | Rectangle::IDs::B; // Error
    ...
    return 0;
}

共有1个答案

祝高超
2023-03-14

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

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

有用法:

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
}

演示

 类似资料:
  • 当将MongoDB的$in子句与Aggregate一起使用时,That在参数数量上有任何最大限制吗? 例如 在id数组中,我可以传递多少id? 目前,我没有遇到任何问题的ids长度达到50,000...但是为了安全起见,我想知道最大限度。 我试着在Mongo doc上搜索,但是什么也没找到。 先谢谢你。

  • 我正在尝试创建一个模板函子,它将使用任意数量的参数作为参数对象和成员函数。我不知道如何用模板正确地编写代码。 如果我使对象::方法没有参数-代码编译。但是有参数-没有。 严重性代码描述项目文件行抑制状态错误C2664'int Builder::运算符()(T

  • 问题内容: 我是Java的新手,我想问这个问题只是为了帮助我更好地理解OOP。 假设我要定义一个名为“小时”的新类。要实例化该类,我们需要指定一个整数以指示该实例的小时数。 因此,当我们在此处定义小时类别时,构造函数的参数应在[0,24)范围内。如果定义了超出此范围的参数,我们如何定义这样的参数?我可以抛出错误吗? 谢谢。 问题答案: 如果您希望 编译器 捕获错误,则可以为小时定义一个枚举,然后将

  • 我试图在类型s. t上专门化一个类。它忽略了给定类型的恒定性。在这种情况下,该类型是一个模板模板参数: 上面的代码在GCC 4.8.4和clang 5.0(with-std=c 11)中都抱怨bar在与匹配FOFType模板参数化的类一起使用时未定义。即使我删除了sfinae参数,仍然无法找到特化。 这个问题的一个例子可以在这里找到:https://godbolt.org/g/Cjci9C.在上面

  • 这行不通,因为premiumStrings::contains可以接受任何对象,而不仅仅是字符串。可以将其替换为<代码>(字符串s)- (具体来说,问题是

  • 我有这样的代码: 这段代码的目的是:如果是或的子类,则将推导为,否则推导为