c++ - Same_as अवधारणा दो बार टाइप समानता की जाँच क्यों करती है?
c++20 concept (2)
दिलचस्प सवाल। मैंने हाल ही में एंड्रयू सटन की बातचीत को कॉन्सेप्ट पर देखा है, और प्रश्नोत्तर सत्र में किसी ने निम्नलिखित प्रश्न पूछा है: (निम्न लिंक में टाइमस्टैम्प): CppCon 2018: एंड्रयू सटन "60 में अवधारणाएं: सब कुछ आपको जानना चाहिए और कुछ भी नहीं जिसे आप नहीं चाहते"
इसलिए यह सवाल उबलता है:
If I have a concept that says A && B && C, another says C && B && A, would those be equivalent?
एंड्रयू ने हां में उत्तर दिया, लेकिन इस तथ्य को इंगित किया कि संकलक में कुछ आंतरिक विधियां (जो उपयोगकर्ता के लिए पारदर्शी हैं) अवधारणाओं को परमाणु तार्किक प्रस्तावों (
atomic constraints
शब्द के रूप में
atomic constraints
) को विघटित करने के लिए कहते हैं और जांचें कि क्या वे समकक्ष हैं।
अब देखें कि cppreference
std::same_as
बारे में क्या कहता है
std::same_as
:
std::same_as<T, U>
subsumesstd::same_as<U, T>
और इसके विपरीत।
यह मूल रूप से "इफ-एंड-ओनली-इफ" रिश्ता है: वे एक-दूसरे को प्रभावित करते हैं। (तार्किक समानता)
मेरा अनुमान है कि यहाँ परमाणु अड़चनें
std::is_same_v<T, U>
।
जिस तरह से कंपाइलर
std::is_same_v
इलाज करते हैं
std::is_same_v
उन्हें लगता है कि
std::is_same_v<T, U>
और
std::is_same_v<U, T>
दो अलग-अलग बाधाओं के रूप में हैं (वे अलग-अलग संस्थाएं हैं!)।
इसलिए यदि आप
std::same_as
लागू करते हैं
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
उत्सर्जन करता है
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<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>;
कोड संकलित करता है।
https://en.cppreference.com/w/cpp/concepts/same_as पर समान_स अवधारणा के संभावित कार्यान्वयन को देखते हुए मैंने देखा कि कुछ अजीब हो रहा है।
namespace detail {
template< class T, class U >
concept SameHelper = std::is_same_v<T, U>;
}
template< class T, class U >
concept same_as = detail::SameHelper<T, U> && detail::SameHelper<U, T>;
पहला सवाल यह है कि एक
SameHelper
अवधारणा को क्यों किया जाता है?
दूसरी बात यह है कि यदि
T
और
U
के समान ही है तो
same_as
समान है?
क्या यह बेमानी नहीं है?
std::is_same
को सही के रूप में परिभाषित किया जाता है यदि और केवल यदि:
T और U समान cv-योग्यता के साथ एक ही प्रकार का नाम देते हैं
जहां तक मुझे पता है, मानक "एक ही प्रकार" के अर्थ को परिभाषित नहीं करता है, लेकिन प्राकृतिक भाषा और तर्क में "समान" एक समतुल्य संबंध है और इस प्रकार यह सराहनीय है।
इस धारणा को देखते हुए, जिसे मैं
is_same_v<T, U> && is_same_v<U, V>
,
is_same_v<T, U> && is_same_v<U, V>
वास्तव में बेमानी होगा।
लेकिन
same_as
संदर्भ में
is_same_v
निर्दिष्ट नहीं है;
यह केवल प्रदर्शनी के लिए है।
दोनों के लिए स्पष्ट जांच
same-as-impl
same_as
लिए कार्यान्वयन की अनुमति देती है ताकि
same_as
बिना
same_as
को संतुष्ट किया जा सके।
इसे इस तरह से निर्दिष्ट करना वास्तव में वर्णन करता है कि यह अवधारणा कैसे प्रतिबंधित किए बिना व्यवहार करती है कि इसे कैसे लागू किया जा सकता है।
वास्तव में इस दृष्टिकोण को
is_same_v
संदर्भ में निर्दिष्ट करने के बजाय क्यों चुना गया, मुझे नहीं पता।
चुने हुए दृष्टिकोण का एक फायदा यकीनन यह है कि दो परिभाषाएं एक-दूसरे से जुड़ी हुई हैं।
एक दूसरे पर निर्भर नहीं है।