■ Определение проблемы _________________________
!!
You can skip here and directly go to
■ Question Summary !!
Я разработал гибкий, но эффективный для использования в памяти * класс 1015 *, который подходит для различных ситуаций, имея только селективные черты внутри: ссылка
Плюс, я дал ID для каждой черты, которая используется, когда пользователь хочет запрашивать только указанные c черты класса.
Я написал свой собственный класс, удовлетворяющий этим свойствам, используя множественное наследование из неназванных перечислений с variadi c template .
См. ниже:
▼ 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...
};
▼ Triangle.h
#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
, то, что видит компилятор, может выглядеть как это:
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(...)
с побитовым |operator
, например:
myTri.ComputeTraits(MyTri::IDs::AREA | MyTri::IDs::PERIMETER); // Compute area and perimeter
Проблема возникает здесь : предположим, есть Rectangle.h
и Pentagon.h
, ... NthPolygon.h
, таким же образом.
Я хочу, чтобы каждый из моих пользовательских типов многоугольников получал строго типизированный параметр для его ComputeTrait(...)
(поэтому я использовал для него класс enum), чтобы избежать глупости операции, выполняющие смешанных типов многоугольников , таких как
myTri.ComputeTraits(MyTri::IDs::AREA | MyRect::IDs::PERIMETER); // Mixed traits of a triangle and of a rectangle.
Поэтому я хочу перегрузить |operator
, что занимает только безымянное перечисление с в каждой области действия NthPolygon::IDs::...
.
Я пытался написать перегруженный шаблонный оператор внутри private
области действия NthPolygon::IDs::...
, но это не удалось, так как перегрузка оператора в классе всегда принимает первый параметр как сам по себе: ссылка
Не удалось также сделать его friend
глобальной области видимости, поскольку для каждого N-го класса Polygon будет перегружено более 1 |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;
■ Краткое изложение вопросов _________________________
Как можно составить перегруженная табличка operator|
принимает только параметры (безымянные перечисления) из указанного класса c?
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;
}