C ++ 20 अवधारणाएं: टेम्पलेट तर्क कई अवधारणाओं के लिए योग्य होने पर कौन सा टेम्पलेट विशेषज्ञता चुना जाता है?


23

दिया हुआ :

#include <concepts>
#include <iostream>

template<class T>
struct wrapper;

template<std::signed_integral T>
struct wrapper<T>
{
    wrapper() = default;
    void print()
    {
        std::cout << "signed_integral" << std::endl;
    }
};

template<std::integral T>
struct wrapper<T>
{
    wrapper() = default;
    void print()
    {
        std::cout << "integral" << std::endl;
    }
};

int main()
{
    wrapper<int> w;
    w.print(); // Output : signed_integral
    return 0;
}

ऊपर दिए गए कोड से, intदोनों std::integralऔर std::signed_integralअवधारणा के लिए योग्य हैं ।

आश्चर्यजनक रूप से यह संकलन और GCC और MSVC दोनों संकलकों पर "हस्ताक्षरित_इन्टेग्रल" प्रिंट करता है। मैं उम्मीद कर रहा था कि यह "पहले से परिभाषित टेम्पलेट टेम्पलेट" की तर्ज पर एक त्रुटि के साथ विफल हो जाएगा।

ठीक है, यह कानूनी रूप से उचित है, लेकिन std::signed_integralइसके बजाय क्यों चुना गया std::integral? क्या मानक नियमों में कोई नियम निर्धारित किया गया है कि कौन-सी टेम्पलेट विशेषज्ञता तब चुनी जाती है जब कई तर्क टेम्पलेट तर्क के लिए योग्य होते हैं?


मैं यह नहीं कहूंगा कि यह केवल इस तथ्य से कानूनी है कि संकलक इसे स्वीकार करते हैं, खासकर इसे अपनाने के शुरुआती चरणों में।
स्लाव

@ इस मामले में स्लाव है, अवधारणाओं को सावधानीपूर्वक डिज़ाइन किया गया है ताकि वे एक-दूसरे को सहज तरीके से
समझें

@GuillaumeRacicot यह ठीक है, मैंने अभी टिप्पणी की है कि "यह कानूनी है क्योंकि संकलक ने इसे स्वीकार किया है" यह भ्रामक है। मैंने यह नहीं कहा कि यह कानूनी नहीं है।
स्लाव

जवाबों:


14

ऐसा इसलिए है क्योंकि अवधारणाएं दूसरों की तुलना में अधिक विशिष्ट हो सकती हैं, थोड़ा सा कैसे टेम्पलेट खुद को आदेश देता है। इसे बाधाओं का आंशिक आदेश कहा जाता है

अवधारणाओं के मामले में, वे एक दूसरे की सदस्यता लेते हैं जब वे समतुल्य बाधाओं को शामिल करते हैं। उदाहरण के लिए, यहां बताया गया है कि कैसे std::integralऔर कैसे std::signed_integralलागू किया जाता है:

template<typename T>
concept integral = std::is_integral_v<T>;

template<typename T> //   v--------------v---- Using the contraint defined above
concept signed_integral = std::integral<T> && std::is_signed_v<T>;

संकलक को सामान्य करने से यह संवेदी अभिव्यक्ति को उबालता है:

template<typename T>
concept integral = std::is_integral_v<T>;

template<typename T>
concept signed_integral = std::is_integral_v<T> && std::is_signed_v<T>;

इस उदाहरण में, पूरी तरह से signed_integralनिहित है integral। तो एक अर्थ में, एक हस्ताक्षरित अभिन्न एक अभिन्न की तुलना में "अधिक विवश" है।

मानक इसे इस तरह लिखते हैं:

से [temp.func.order] / 2 (जोर मेरा):

आंशिक ऑर्डरिंग का चयन करता है कि कौन से दो फ़ंक्शन टेम्प्लेट बदले में प्रत्येक टेम्पलेट को बदलकर दूसरे की तुलना में अधिक विशिष्ट हैं (फ़ंक्शन अगले पैराग्राफ देखें) और फ़ंक्शन प्रकार का उपयोग करके टेम्पलेट तर्क कटौती का प्रदर्शन करें। कटौती प्रक्रिया यह निर्धारित करती है कि क्या एक टेम्पलेट दूसरे की तुलना में अधिक विशिष्ट है। यदि ऐसा है, तो अधिक विशिष्ट टेम्पलेट आंशिक ऑर्डरिंग प्रक्रिया द्वारा चुना गया एक है। यदि दोनों कटौतियां सफल होती हैं, तो आंशिक आदेश [temp.constr.order] में नियमों द्वारा वर्णित अधिक विवश टेम्पलेट का चयन करता है ।

इसका मतलब है कि यदि किसी टेम्पलेट के लिए कई संभावित प्रतिस्थापन हैं और दोनों आंशिक ऑर्डरिंग से चुने गए हैं, तो यह सबसे विवश टेम्पलेट का चयन करेगा।

से [temp.constr.order] / 1 :

एक बाधा पी subsumes की कोई समस्या क्यू यदि और केवल यदि, हर वियोगी खंड के लिए पी मैं की वियोगी सामान्य रूप में पी , पी मैं हर संयोजक खंड subsumes क्यू जे के संयुक्त सामान्य रूप में क्यू , जहां

  • एक वियोगी खंड पी मैं एक संयोजक खंड subsumes क्यू j यदि और केवल यदि वहाँ एक परमाणु बाधा मौजूद पी आइए में पी मैं जिसके लिए वहाँ एक परमाणु बाधा मौजूद है क्यू जेबी में क्यू जे ऐसी है कि पी आइए subsumes क्यू जेबी , और

  • एक परमाणु बाधा एक अन्य परमाणु बाधा subsumes बी यदि और केवल यदि एक और बी नियमों में वर्णित का उपयोग कर समान हैं [temp.constr.atomic]

यह सबस्क्रिप्शन एल्गोरिथ्म का वर्णन करता है जो संकलक का उपयोग अवरोधों को आदेश देने के लिए करता है, और इसलिए अवधारणाएं।


2
ऐसा लग रहा है कि आप एक पैराग्राफ के बीच में पीछे चल रहे हैं ...
ShadowRanger

11

C ++ 20 में यह निर्णय लेने के लिए एक तंत्र है कि जब एक विशेष विवश इकाई दूसरे की तुलना में "अधिक विवश" है। यह कोई साधारण बात नहीं है।

यह अपने परमाणु घटकों में एक बाधा को तोड़ने की अवधारणा के साथ शुरू होता है, एक प्रक्रिया जिसे बाधा सामान्यीकरण कहा जाता है । यहाँ पर जाना बड़ा और बहुत जटिल है, लेकिन मूल विचार यह है कि एक बाधा में प्रत्येक अभिव्यक्ति अपने परमाणु वैचारिक टुकड़ों में, पुनरावर्ती रूप से टूट जाती है, जब तक कि आप एक घटक उप-अभिव्यक्ति तक नहीं पहुंचते हैं जो एक अवधारणा नहीं है।

तो यह देखते हुए, आइए देखें कि कैसे integralऔर signed_integralअवधारणाओं को परिभाषित किया गया है :

template<class T>
  concept integral = is_integral_v<T>;
template<class T>
  concept signed_­integral = integral<T> && is_signed_v<T>;

का अपघटन integralसिर्फ है is_integral_v। का अपघटन signed_integralहै is_integral_v && is_signed_v

अब, हम बाधा निर्वाह की अवधारणा पर आते हैं । यह एक तरह से जटिल है, लेकिन मूल विचार यह है कि एक बाधा C1 को C2 के प्रत्येक उप-अभिव्यक्ति में C1 के अपघटन समाहित होने पर एक बाधा C2 "सब्स्टीट्यूट" कहा जाता है। हम देख सकते हैं कि integralवह उपसमुच्चय नहीं है signed_integral, लेकिन उपसर्ग signed_integral करता हैintegral , क्योंकि इसमें सब कुछ शामिल integralहै।

अगला, हम विवश संस्थाओं को आदेश देने के लिए आते हैं:

एक घोषणा डी 1 कम से कम एक घोषणा डी 2 के रूप में विवश है अगर * डी 1 और डी 2 दोनों विवश घोषणाएं हैं और डी 1 की संबद्ध बाधाएं डी 2 की उन सबको मानती हैं; या * D2 में कोई संबद्ध बाधा नहीं है।

क्योंकि signed_integralसदस्यता integral, <signed_integral> wrapper"के रूप में कम से कम विवश है" के रूप में है <integral> wrapper। हालांकि, प्रतिवर्ती सत्य नहीं है, क्योंकि प्रतिगमन के प्रतिवर्ती नहीं होने के कारण।

इसलिए, "अधिक विवश" संस्थाओं के लिए नियम के अनुरूप:

एक घोषणा डी 1 एक और घोषणा डी 2 की तुलना में अधिक विवश है जब डी 1 कम से कम डी 2 के रूप में विवश है, और डी 2 कम से कम डी 1 के रूप में विवश नहीं है।

चूँकि <integral> wrapper, कम से कम उतने विवश नहीं हैं जितना <signed_integral> wrapperकि बाद वाले को पूर्व की तुलना में अधिक विवश माना जाता है।

और इसलिए, जब दोनों में से दोनों आवेदन कर सकते हैं, तो अधिक विवश घोषणा जीत जाती है।


ध्यान रखें कि जब अभिव्यक्ति का सामना नहीं होता है तो बाधा निर्वाह के नियम बंद हो जाते हैं concept। तो अगर आपने ऐसा किया है:

template<typename T>
constexpr bool my_is_integral_v = std::is_integral_v<T>;

template<typename T>
concept my_signed_integral = my_is_integral_v<T> && std::is_signed_v<T>;

इस मामले में, सदस्यता my_signed_integral नहीं होगीstd::integral । भले ही my_is_integral_vयह परंपरागत रूप से परिभाषित किया गया हो std::is_integral_v, क्योंकि यह एक अवधारणा नहीं है, C ++ की सदस्यता नियम इसके माध्यम से यह निर्धारित नहीं कर सकते हैं कि वे समान हैं।

इसलिए निर्विवाद नियम आपको परमाणु अवधारणाओं पर संचालन से बाहर अवधारणाओं का निर्माण करने के लिए प्रोत्साहित करते हैं।


3

Partial_ordering_of_constraints के साथ

एक बाधा P को बाधा Q को कम करने के लिए कहा जाता है यदि यह सिद्ध किया जा सकता है कि P का अर्थ है P और Q में परमाणु अवरोधों की पहचान तक।

तथा

सदस्यता संबंध बाधाओं के आंशिक क्रम को परिभाषित करता है, जिसका उपयोग यह निर्धारित करने के लिए किया जाता है:

  • अधिभार संकल्प में एक गैर टेम्पलेट समारोह के लिए सबसे अच्छा व्यवहार्य उम्मीदवार
  • एक अधिभार सेट में एक गैर-टेम्पलेट फ़ंक्शन का पता
  • एक टेम्पलेट टेम्पलेट तर्क के लिए सबसे अच्छा मैच
  • वर्ग टेम्पलेट विशेषज्ञता के आंशिक आदेश
  • फ़ंक्शन टेम्प्लेट का आंशिक क्रम

और अवधारणा अवधारणा को std::signed_integralग्रहण करती std::integral<T>है:

template < class T >
concept signed_integral = std::integral<T> && std::is_signed_v<T>;

तो आपका कोड ठीक है, जैसा std::signed_integralकि अधिक "विशेष" है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.