मैंने एसओ पर यहां पर एक सूत्र का अनुसरण किया कि कैसे एक आउटपुट योग्य विशेषता वर्ग को कार्यान्वित किया जाए ताकि संकलन समय पर जांच की जा सके कि एक प्रकार std::ostream पर आउटपुट हो सकता है या नहीं। वर्ग का कार्यान्वयन निम्नलिखित है:

template<typename U>
        struct OstreamOutputableTrait
        {
            template<typename T>
            static decltype(std::declval<std::ostream&>() << std::declval<T>(), std::true_type{} )
            IsOstreamOutputtable(std::ostream& os, const T& var) {}

            // for vector<T>
            template<typename T>
            static std::false_type IsOstreamOutputtable(std::ostream& os, const std::vector<T>& var)
            {}

            template<typename > static auto IsOstreamOutputtable(...) {
                return std::false_type {};
            }
            static const auto value =
                    decltype(IsOstreamOutputtable(std::declval<std::ostream&>(), std::declval<U>()))::value;
        };

// operator implementation
        template<typename Key, typename T>
        std::ostream& operatorImpl(std::ostream& os, const std::map<Key,T>& map, const std::true_type& ) {
            for(auto it = map.begin(); it!= map.end(); ++it)
                os << "(" << (*it).first << " ; " << (*it).second << ")" <<"\n";
            return os;
        }

        template<typename Key, typename T>
        std::ostream& operatorImpl(std::ostream& os, const std::map<Key, T>& map, const std::false_type& ) {
            os << "\nElements of the map are not printable.\n";
            return os;
        }

        // operator << on <Key, value> maps
        template<typename Key, typename T>
        std::ostream& operator<<(std::ostream& os, const std::map<Key, T>& map)
        {
            // redirect using SFINAE to correct Impl of the operator<< : ty always returns true!
            auto ty = std::integral_constant<bool,
            OstreamOutputableTrait<typename std::decay_t<T> >::value &&
            OstreamOutputableTrait<typename std::decay_t<Key> >::value>();

            operatorImpl(os, map, ty);
            return os;
        }

मेरे पास समस्या यह है कि वेरिएबल ty ऊपर दिए गए फ़ंक्शन में हमेशा std::true_type देता है। क्या इसका मतलब यह है कि दोनों <Key,T> std::map टेम्प्लेट वर्ग के टाइपनाम STL में डिफ़ॉल्ट रूप से std::ostream पर आउटपुट योग्य हैं? अगर कोई समझा सकता है कि मैं कुछ गलत कहां कर रहा हूं, तो इससे मुझे बहुत मदद मिलेगी।

धन्यवाद अमीन

0
Amine 1 अप्रैल 2020, 14:49

2 जवाब

आपकी त्रुटि IsOstreamOutputtable() के विविध संस्करण को घोषित करने में है

template <typename>
static auto IsOstreamOutputtable (...)
 { return std::false_type {}; }

आप इसे एक टेम्पलेट पैरामीटर के साथ टेम्पलेट फ़ंक्शन के रूप में घोषित करते हैं जिसे तर्कों से नहीं निकाला जा सकता है।

इसलिए, जब आप फ़ंक्शन को decltype() से कॉल करते हैं

static const auto value =
   decltype(IsOstreamOutputtable(std::declval<std::ostream&>(), std::declval<U>()))::value;

संकलक विविध संस्करण को ध्यान में नहीं रख सकता है।

समाधान।

(1) आप IsOstreamOutputtable() को कॉल करने वाले टेम्प्लेट पैरामीटर को स्पष्ट कर सकते हैं

   // ..........................VVV   explicit template parameter
   decltype(IsOstreamOutputtable<U>(std::declval<std::ostream&>(), std::declval<U>()))::value;

तो संकलक विविध संस्करण का उपयोग कर सकता है,

समस्या: यह समाधान std::vector संस्करण के लिए काम नहीं करता

(2) (बेहतर) आप IsOstreamOutputtable() के विविध संस्करण को गैर-टेम्पलेट वाला बना सकते हैं

// no needs of template
static auto IsOstreamOutputtable (...)
 { return std::false_type {}; }

ऑफ टॉपिक: IsOstreamOutputtable() विधियों को केवल decltype() के अंदर ही बुलाया जाता है, इसलिए परिभाषित करने की कोई आवश्यकता नहीं है, आपको केवल उन्हें घोषित करना है। (और यदि आप उन्हें परिभाषित करते हैं, तो कृपया सुसंगत रहें: std::true_type लौटने वाली विधि के लिए शरीर खाली नहीं हो सकता)।

पिछला रिटर्न प्रकार, और अन्य छोटे सरलीकरणों का उपयोग करके, आपकी टाइपराइटिंग को थोड़ा कम किया जा सकता है

template <typename U>
struct OstreamOutputableTrait
 {
   template <typename T>
   static auto IsOstreamOutputtable (T const & var)
      -> decltype( std::declval<std::ostream&>() << var, std::true_type{} );

   // special case for vector<T>
   template <typename T>
   static std::false_type IsOstreamOutputtable (std::vector<T> const &);

   static std::false_type IsOstreamOutputtable (...);

   static constexpr auto value
      = decltype(IsOstreamOutputtable(std::declval<U>()))::value;
 };
0
max66 1 अप्रैल 2020, 18:05
बहुत बहुत धन्यवाद @ max66! मैं अब से आपके दिशानिर्देशों का पालन करूंगा। तो अगर मैं सही ढंग से समझता हूं, variadic template फ़ंक्शन की परिभाषा के अंदर कोई पैरामीटर का उपयोग नहीं कर रहा है, तो संकलक इसे गैर-टेम्पलेट फ़ंक्शन के रूप में मानता है, और इसलिए SFINAE तंत्र के लिए संकलन समय पर अनदेखा किया जाता है? धन्यवाद
 – 
Amine
8 अप्रैल 2020, 19:48
- क्षमा करें, लेकिन मुझे समझ में नहीं आता कि "वैरिएडिक टेम्प्लेट के अंदर कोई पैरामीटर नहीं का उपयोग करना <टाइपनाम> फ़ंक्शन की परिभाषा" से आपका क्या मतलब है। कृपया, क्या आप एक व्यावहारिक उदाहरण (शायद प्रश्न में) लिख सकते हैं?
 – 
max66
8 अप्रैल 2020, 21:03

@ मैक्स 66,

मेरा विचार था कि:

template<typename T>
            static decltype(std::declval<std::ostream&>() << std::declval<T>(), std::true_type{} )
            IsOstreamOutputtable(std::ostream& os, const T& var) {}

जाँच करेगा कि प्रत्येक प्रकार T के लिए जो operator<< का उपयोग करके आउटपुट किया जा सकता है, decltype std::true_type का प्रकार लौटाएगा। इस संदर्भ में, विविध अधिभार:

template<typename > static auto IsOstreamOutputtable(...) {
                return std::false_type {};
            }

भ्रम पैदा करने के अलावा कोई उपयोगिता नहीं है। ऐसा कहकर, अगर मैं वाक्यविन्यास का उपयोग करता हूं:

decltype(IsOstreamOutputtable<U>(std::declval<std::ostream&>(), std::declval<U>()))::value;

क्या वैरिएडिक फ़ंक्शन की प्राथमिकता पहले वाले पर होगी जो std::true_type लौटाता है?

0
Amine 8 अप्रैल 2020, 21:40