2016-02-09 7 views
11

मुझे कभी-कभी सामान्य दिनचर्या लिखने की आवश्यकता होती है जिसे वस्तुओं के कंटेनर पर लागू किया जा सकता है, या ऐसे कंटेनरों का मानचित्र (यानी मानचित्र में प्रत्येक कंटेनर को संसाधित करता है)। एक दृष्टिकोण नक्शा प्रकार के लिए अलग दिनचर्या लिखने के लिए है, लेकिन मुझे लगता है कि यह एक नियमित है कि इनपुट के दोनों प्रकार के लिए काम करता है के लिए और अधिक प्राकृतिक और कम शब्दाडंबरपूर्ण हो सकता है:जांचना कि कोई प्रकार नक्शा है

template <typename T> 
auto foo(const T& items) 
{ 
    return foo(items, /* tag dispatch to map or non-map */); 
} 

क्या करने के लिए एक सुरक्षित, स्वच्छ रास्ता है यह टैग प्रेषण?

#include <type_traits> 
#include <utility> 

namespace detail 
{ 
    template <typename T, typename = void> 
    struct IsMap : std::false_type {}; 

    template <typename T> 
    struct IsMap<T, std::enable_if_t< 
         std::is_same<typename T::value_type, 
            std::pair<const typename T::key_type, 
               typename T::mapped_type> 
         >::value> 
    > : std::true_type {}; 
} 

template <typename T> 
constexpr bool is_map = detail::IsMap<T>::value; 

namespace { template <bool> struct MapTagImpl {}; } 
using MapTag = MapTagImpl<true>; 
using NonMapTag = MapTagImpl<false>; 

template <typename T> 
using MapTagType = MapTagImpl<is_map<T>>; 
+2

जांचें कि क्या यह 'key_type' और' mapped_type' प्रकारों को नेस्टेड किया गया है? –

उत्तर

12

मौजूदा std::map का बहुत विशिष्ट गुणों के लिए जवाब परीक्षण, या तो है कि

+0

'is_mappish_impl' ने मुझे चकित कर दिया। :) – erip

+0

हालांकि, यह समाधान केवल तभी मान्य होता है जब गैर मानक नक्शा मानक सहयोगी कंटेनर के इंटरफ़ेस को लागू करता है, यह भी टूट सकता है। –

+2

@ डेविडहैम, हां जाहिर है। यदि प्रकार किसी विशिष्ट इंटरफ़ेस को लागू नहीं करता है तो संभवतः आप उस इंटरफ़ेस पर निर्भर टेम्पलेट फ़ंक्शन पर प्रेषण नहीं करना चाहते हैं। नक्शा इंटरफेस के जो भी हिस्सों ओपी के 'फू' के लिए प्रासंगिक हैं, यह देखने के लिए आसानी से तैयार किया जा सकता है कि मानचित्र के साथ काम करता है, क्योंकि "मानचित्र" की परिभाषा फ़ंक्शन के लिए प्रासंगिक है। –

1

यहाँ मैं के साथ आया है यह std::map का एक विशेषज्ञता है (std::unordered_map के लिए गलत होगा या std::map के समान इंटरफ़ेस वाले गैर-मानक प्रकार), या परीक्षण करें कि value_type बिल्कुलहै(जो multimap और unordered_map के लिए सच होगा, लेकिन समान इंटरफेस वाले गैर-मानक प्रकारों के लिए गलत)।

यह केवल परीक्षण है कि यह key_type और mapped_type सदस्यों प्रदान करता है, और operator[] साथ पहुँचा जा सकता है, तो कहते हैं कि यह नहीं है कि std::multimap mappish है:

#include <type_traits> 

namespace detail { 
    // Needed for some older versions of GCC 
    template<typename...> 
    struct voider { using type = void; }; 

    // std::void_t will be part of C++17, but until then define it ourselves: 
    template<typename... T> 
    using void_t = typename voider<T...>::type; 

    template<typename T, typename U = void> 
    struct is_mappish_impl : std::false_type { }; 

    template<typename T> 
    struct is_mappish_impl<T, void_t<typename T::key_type, 
            typename T::mapped_type, 
            decltype(std::declval<T&>()[std::declval<const typename T::key_type&>()])>> 
    : std::true_type { }; 
} 

template<typename T> 
struct is_mappish : detail::is_mappish_impl<T>::type { }; 

क्योंकि is_mappish एक "आधार विशेषता" या तो true_type की है या false_type तुम इतनी तरह उस पर प्रेषण कर सकते हैं:

template <typename T> 
auto foo(const T& items, true_type) 
{ 
    // here be maps 
} 

template <typename T> 
auto foo(const T& items, false_type) 
{ 
    // map-free zone 
} 

template <typename T> 
auto foo(const T& items) 
{ 
    return foo(items, is_mappish<T>{}); 
} 

या आप पूरी तरह से भेजने से बच सकते हैं, और सिर्फ अधिभार foo नक्शे और गैर-मानचित्रों के लिए:

template <typename T, 
      std::enable_if_t<is_mappish<T>{}, int> = 0> 
auto foo(const T& items) 
{ 
    // here be maps 
} 

template <typename T, 
      std::enable_if_t<!is_mappish<T>{}, int> = 0> 
auto foo(const T& items) 
{ 
    // map-free zone 
} 
+1

'true_type' या' false_type' से प्राप्त करना 'स्थिर constexpr बूल मान' को परिभाषित करने से सरल है। इसके अलावा आपकी विशेषता मल्टीमैप्स के लिए भी सच है, जो वांछनीय नहीं हो सकती है (उनके पास एक ही इंटरफ़ेस नहीं है)। –

+0

@ जोनाथन वाकई अच्छे अंक, ने जवाब अपडेट किया है। धन्यवाद! – Daniel

10

यह मेरे लिए काम किया है, 100%, हालांकि परीक्षण नहीं:

template <class T> 
struct isMap { 
    static constexpr bool value = false; 
}; 

template<class Key,class Value> 
struct isMap<std::map<Key,Value>> { 
    static constexpr bool value = true; 
}; 

int main() { 
    constexpr bool b1 = isMap<int>::value; //false 
    constexpr bool b2 = isMap<std::vector<int>>::value; //false 
    constexpr bool b3 = isMap<std::map<int,std::string>>::value; //true 
    constexpr bool b4 = isMap<std::future<int>>::value; //false 
} 
+2

यह ध्यान देने योग्य है कि यह केवल 'std :: map' के लिए काम करता है, न कि अन्य' मानचित्र 'प्रकार (उदा। 'Std :: unordered_map')। मुझे शायद इस सवाल में और अधिक विशिष्ट होना चाहिए था। – Daniel

+0

@ डैनियल फिर अनॉर्डर्ड_मैप के लिए एक विशेषज्ञता जोड़ें यदि आवश्यक – Laurijssen

+0

@ डैनियल मैं मानता हूं कि आपने मानक नियमित मानचित्र के बारे में बात की थी। इसे आसानी से std :: unordered_map समर्थन में परिवर्तित किया जा सकता है, और बाद में AnyMap है। हालांकि, मुझे संदेह है कि कोई भी उसी प्रोजेक्ट में 1-2 प्रकार के मानचित्रों का अधिक उपयोग करेगा .. –

संबंधित मुद्दे