दिलचस्प सवाल। मैंने हाल ही में एंड्रयू सटन की बातचीत को कॉन्सेप्ट पर देखा है, और प्रश्नोत्तर सत्र में किसी ने निम्नलिखित प्रश्न पूछा है: (निम्न लिंक में टाइमस्टैम्प):
CppCon 2018: एंड्रयू सटन "60 में अवधारणाएं: सब कुछ आपको जानना चाहिए और कुछ भी नहीं जिसे आप नहीं चाहते"
इसलिए यह सवाल उबलता है: If I have a concept that says A && B && C, another says C && B && A, would those be equivalent?
एंड्रयू ने हां में उत्तर दिया, लेकिन इस तथ्य को इंगित किया कि संकलक में कुछ आंतरिक विधियां (जो उपयोगकर्ता के लिए पारदर्शी हैं) अवधारणाओं को परमाणु तार्किक प्रस्तावों में व्याख्यायित करना है ( atomic constraints
जैसा कि एंड्रयू ने इस शब्द को कहा है) और जांचें कि क्या वे हैं बराबर।
अब देखो क्या cppreference के बारे में कहते हैं std::same_as
:
std::same_as<T, U>
सदस्यता std::same_as<U, T>
और इसके विपरीत।
यह मूल रूप से "इफ-एंड-ओनली-इफ" रिश्ता है: वे एक-दूसरे को प्रभावित करते हैं। (तार्किक समानता)
मेरा अनुमान है कि यहाँ परमाणु अड़चनें हैं std::is_same_v<T, U>
। जिस तरह से संकलक व्यवहार करते हैं वे std::is_same_v
उन्हें सोच सकते हैं std::is_same_v<T, U>
और std::is_same_v<U, T>
दो अलग-अलग बाधाओं के रूप में (वे अलग-अलग संस्थाएं हैं!)। इसलिए यदि आप std::same_as
उनमें से केवल एक का उपयोग करके लागू करते हैं:
template< class T, class U >
concept same_as = detail::SameHelper<T, U>;
तब std::same_as<T, U>
और std::same_as<U, T>
विभिन्न परमाणु अवरोधों के लिए "विस्फोट" होगा और समतुल्य नहीं बनेंगे।
खैर, संकलक देखभाल क्यों करता है?
इस उदाहरण पर विचार करें :
#include <type_traits>
#include <iostream>
#include <concepts>
template< class T, class U >
concept SameHelper = std::is_same_v<T, U>;
template< class T, class U >
concept my_same_as = SameHelper<T, U>;
// template< class T, class U >
// concept my_same_as = SameHelper<T, U> && SameHelper<U, T>;
template< class T, class U> requires my_same_as<U, T>
void foo(T a, U b) {
std::cout << "Not integral" << std::endl;
}
template< class T, class U> requires (my_same_as<T, U> && std::integral<T>)
void foo(T a, U b) {
std::cout << "Integral" << std::endl;
}
int main() {
foo(1, 2);
return 0;
}
आदर्श रूप से, my_same_as<T, U> && std::integral<T>
उपसमूह my_same_as<U, T>
; इसलिए, कंपाइलर को दूसरे टेम्प्लेट स्पेशलाइजेशन का चयन करना चाहिए, इसके अलावा ... ऐसा नहीं है: कंपाइलर एक त्रुटि का उत्सर्जन करता है error: call of overloaded 'foo(int, int)' is ambiguous
।
इसके पीछे कारण यह है कि चूंकि my_same_as<U, T>
और my_same_as<T, U>
एक-दूसरे को सब्सक्राइब नहीं करते हैं, my_same_as<T, U> && std::integral<T>
और my_same_as<U, T>
अतुलनीय हो जाते हैं (सब्सक्राइब के संबंध में बाधाओं के आंशिक रूप से आदेशित सेट पर)।
हालाँकि, यदि आप प्रतिस्थापित करते हैं
template< class T, class U >
concept my_same_as = SameHelper<T, U>;
साथ में
template< class T, class U >
concept my_same_as = SameHelper<T, U> && SameHelper<U, T>;
कोड संकलित करता है।
SameHelper<T, U>
कि सच हो सकता है इसका मतलब यह नहींSameHelper<U, T>
हो सकता है।