// tmp_policy // Created by lucas on 22-7-26. // Re-implementation of a typical policy architecture in C++ Template Meta-Programming. #ifndef TMP_POLICY_POLICY_FUNDAMENTALS_H #define TMP_POLICY_POLICY_FUNDAMENTALS_H #include // The container of policy objects. template struct PolicyContainer; // This part of logic should not be accessed by the outside code. namespace NSPolicySelect { // Auxiliary Meta-Function: template constexpr bool IsArrayEmpty // To indicate whether a PolicyContainer is empty or not. // True branch: If the template parameter isn't PolicyContainer, // or is a PolicyContainer with no element, // the meta-function returns true. template constexpr bool IsArrayEmpty = true; // False branch: If the template parameter is a PolicyContainer // with more than one element, // the meta-function returns false. template constexpr bool IsArrayEmpty> = false; // Meta-Function: template struct MajorFilter_; // Remove the policy object whose MajorClass doesn't match with the first policy object. // Also, the primitive template handles with the situation in which the two PolicyContainer are both empty. template struct MajorFilter_ { using type = PolicyContainer<>; }; // Template specialization of MajorFilter_. template struct MajorFilter_, PolicyContainer> { // The main logic of the loop. // Use std::conditional_t to perform branch structure. using type = std::conditional_t< // Condition: Does TCurPolicy contain the same major class as the policy group? std::is_same::value, // True branch: If it does, add TCurPolicy to the policy group. typename MajorFilter_, PolicyContainer>::type, // False branch: If it doesn't, skip TCurPolicy. typename MajorFilter_, PolicyContainer>::type >; // ... and recursively proceed with next element. }; // Template specialization of MajorFilter_. template struct MajorFilter_, PolicyContainer> { // The beginning of the recursion. // Simply put the first policy into the modified policy container. using type = typename MajorFilter_, PolicyContainer>::type; }; // Template specialization of MajorFilter_. template struct MajorFilter_, TEmptyContainer> { // Boundary of recursion: The proceeding policy container has no elements inside. // Therefore, simply return the proceeded policy container. using type = PolicyContainer; }; // Auxiliary type definition: simplify the usage of MajorFilter_. template using MajorFilter = typename MajorFilter_, TPolicyCont>::type; // Meta-Function: template struct MinorCheckInner_. // Check whether the rest policy objects' MinorClass match with the current policy object or not. // It performs as the inner loop of the minor check algorithm. // Also, the primitive template handles with the boundary of recursion. // It simply returns std::true_type when there is no policy object in the PolicyContainer. template struct MinorCheckInner_ { using type = std::true_type; }; // Template specialization of MinorCheckInner_. template struct MinorCheckInner_> { using type = std::conditional_t< // The meta-function checks if two policy objects have the same minor class... std::is_same::value, // ... if yes, simply returns false to end the recursion. std::false_type, // ... if no, proceeds check with TPolicy // and the next policy object in the policy container. typename MinorCheckInner_>::type >; }; // Meta-Function: template struct MinorCheckOuter_. // For each policy object in the policy container, // use MinorCheckInner_ to identify if there are another policy object // having identical minor class. // Also, the primitive template handles with the situation in which // the policy container has no element. template struct MinorCheckOuter_ { using type = std::true_type; }; // Template specialization of MinorCheckOuter_. template struct MinorCheckOuter_> { // The main logic of recursion. using type = std::conditional_t< // Does TCurPolicy and the rest policy objects have the same minor class? MinorCheckInner_>::type::value, // ... if no, proceed with next policy object in the policy container. typename MinorCheckOuter_>::type, // ... if yes, simply returns false and ends the recursion. std::false_type >; }; // Auxiliary template value meta-function definition: MinorCheck. // Check if the TPolicyContainer has more than one element // with the same minor class. // If yes, returns false. // If no, returns true. template constexpr bool MinorCheck = MinorCheckOuter_::type::value; // Template Declaration: template struct PolicySelectionResult. // The template class which describes the policy selection result. template struct PolicySelectionResult; // Template specialization of PolicySelectionResult. // If the PolicyContainer only has one policy object in it, // the PolicySelectionResult simply inherits from the policy object. template struct PolicySelectionResult> : public TPolicy {}; // Template specialization of PolicySelectionResult. // If the PolicyContainer has more than one policy object in it, // the PolicySelectionResult inherits from the first policy object // and the PolicySelectionResult of other policies. // The result contains a definition that is dominant and unambiguous -- // each declaration comes from either Policy Group's initial definition // or the policy object's overwritten definition. template struct PolicySelectionResult> : public TCurPolicy, public PolicySelectionResult> {}; // Template Declaration: template struct Selector_. // The interface for users to get the policy selection result. // TPolicyContainer - the policy container which contains the policy objects. // TPolicyGroup - the original policy group. template struct Selector_; // Template specialization of Selector_. // Restricts the TPolicyContainer can only be type PolicyContainer. template struct Selector_, TPolicyGroup> { // Use access specifier to prevent the users to use the internal types. private: // Use MajorFilter (MajorFilter_) to filter out the policy objects // with unmatched MajorClass. using FilteredPolicy = MajorFilter>; // Check if the policy objects has conflict minor classes. static_assert(MinorCheck, "Minor Class Set Conflict!"); public: // Generate the policy selection result. using type = std::conditional_t< // Is the PolicyContainer empty? IsArrayEmpty, // ... if so, returns the policy group to represent the default definitions. TPolicyGroup, // ... if not, generate policy selection result to represent the user-selected definitions. PolicySelectionResult >; }; // Auxiliary type definition - PolicySelect. // To simplify the usage of Selector_. template using PolicySelect = typename Selector_::type; } // Expose the NSPolicySelect::PolicySelect to global scope. using NSPolicySelect::PolicySelect; #endif //TMP_POLICY_POLICY_FUNDAMENTALS_H