2016-06-03 14 views
7

में विभिन्न स्ट्रिंग प्रकारों के लिए एक संकलन-समय "स्थैतिक-अगर" तर्क लागू करना मैं स्ट्रिंग के कंटेनर पर चलने वाला फ़ंक्शन टेम्पलेट लिखना चाहता हूं, उदाहरण के लिए std::vectorकंटेनर

मैं उसी टेम्पलेट फ़ंक्शन के साथ CString और std::wstring दोनों का समर्थन करना चाहता हूं।

समस्या CString और wstring अलग इंटरफेस है कि, उदाहरण के एक CString की "लंबाई" पाने के लिए, आप के बजाय आप size() या length() फोन wstring के लिए, GetLength() विधि कहते हैं।

अगर हम था एक "स्थिर करता है, तो" सी ++ में सुविधा, मैं की तरह कुछ लिख सकते हैं:

template <typename ContainerOfStrings> 
void DoSomething(const ContainerOfStrings& strings) 
{ 
    for (const auto & s : strings) 
    { 
     static_if(strings::value_type is CString) 
     { 
      // Use the CString interface 
     } 
     static_else_if(strings::value_type is wstring) 
     { 
      // Use the wstring interface 
     } 
    } 
} 

वहाँ वर्तमान में उपलब्ध सी ++ 11/14 के साथ इस लक्ष्य को प्राप्त करने के लिए कुछ टेम्पलेट प्रोग्रामिंग तकनीक है उपकरण?

पुनश्च
मैं जानता हूँ कि यह vector<CString> और vector<wstring> साथ DoSomething() भार के के एक जोड़े लिखने के लिए संभव है, लेकिन यह सवाल की बात नहीं है।
इसके अलावा, मैं इस फ़ंक्शन टेम्पलेट को किसी भी कंटेनर के लिए काम करना चाहता हूं जिस पर आप एक रेंज-लूप का उपयोग करके पुनरावृत्त कर सकते हैं।

+0

https://www.youtube.com/watch?v=hDwhfjBPKv8 बैठक C++ 2015 – odinthenerd

उत्तर

16
#include <type_traits> 

template <typename T, typename F> 
auto static_if(std::true_type, T t, F f) { return t; } 

template <typename T, typename F> 
auto static_if(std::false_type, T t, F f) { return f; } 

template <bool B, typename T, typename F> 
auto static_if(T t, F f) { return static_if(std::integral_constant<bool, B>{}, t, f); } 

template <bool B, typename T> 
auto static_if(T t) { return static_if(std::integral_constant<bool, B>{}, t, [](auto&&...){}); } 

टेस्ट:

template <typename ContainerOfStrings> 
void DoSomething(const ContainerOfStrings& strings) 
{ 
    for (const auto & s : strings) 
    { 
     static_if<std::is_same<typename ContainerOfStrings::value_type, CString>{}> 
     ([&](auto& ss) 
     { 
      // Use the CString interface 
      ss.GetLength(); 
     })(s); 

     static_if<std::is_same<typename ContainerOfStrings::value_type, wstring>{}> 
     ([&](auto& ss) 
     { 
      // Use the wstring interface 
      ss.size(); 
     })(s); 
    } 
} 

DEMO

+2

कोई रास्ता नहीं !! नाइस !!!! – Smeeheey

+0

चूंकि मैं केवल एक ही जवाब को चिह्नित कर सकता हूं, इसलिए मैं इसे चुन रहा हूं क्योंकि यह "स्थैतिक अगर" की संरचना जैसा दिखता है। हालांकि, जब संभव हो, मैं लक्षणों या फ़ंक्शन ओवरलोड जैसे सरल समाधान पसंद करता हूं। अपना कोड साझा करने के लिए धन्यवाद। –

+0

ऐसा लगता है कि लैम्ब्डा को अभी भी संकलित करना है और उचित static_if फ़ंक्शन पर पास किया जाना है, इसलिए यदि यह संकलित करता है तो संभवतया संकलक शीर्ष दो परिभाषाओं में अप्रयुक्त पैरामीटर को अनुकूलित करता है। यह अभी भी बीमार गठित होना चाहिए, हालांकि, जब तक कि मैं कुछ याद नहीं कर रहा हूं ... – patatahooligan

3

आप लंबाई प्राप्त करने के लिए दो भार के प्रदान कर सकता है:

template<typename T> 
std::size_t getLength(T const &str) 
{ 
    return str.size(); 
} 

std::size_t getLength(CString const &str) 
{ 
    return str.GetLength(); 
} 
5

आप समारोह भार के हैं कि क्या आप की जरूरत प्रदान कर सकता है:

size_t getSize(const std::string& str) 
{ 
    return str.size(); 
} 

size_t getSize(const CString& str) 
{ 
    return str.GetLength(); 
} 

template <typename ContainerOfStrings> 
void DoSomething(const ContainerOfStrings& strings) 
{ 
    for (const auto & s : strings) 
    { 
     ... 
     auto size = getSize(s); 
     ... 
    } 
} 
4

एक आम इस हल करने के लिए जिस तरह से आवश्यक निकालने के लिए है एक विशेषता वर्ग में इंटरफ़ेस। कुछ इस तरह:

template <class S> 
struct StringTraits 
{ 
    static size_t size(const S &s) { return s.size(); } 
    // More functions here 
}; 


template <typename ContainerOfStrings> 
void DoSomething(const ContainerOfStrings& strings) 
{ 
    for (const auto & s : strings) 
    { 
     auto len = StringTraits<typename std::decay<decltype(s)>::type>::size(s); 
    } 
} 


// Anyone can add their own specialisation of the traits, such as: 

template <> 
struct StringTraits<CString> 
{ 
    static size_t size(const CString &s) { return s.GetLength(); } 
    // More functions here 
}; 

बेशक, आप तो कल्पना जाने के लिए और समारोह ही बदल प्रकार के आधार पर चयन के अलावा विशेषता चयन अनुमति देने के लिए कर सकते हैं:

template <class ContainerOfStrings, class Traits = StringTraits<typename ContainerOfString::value_type>> 
void DoSomething(const ContainerOfStrings& strings) 
+0

से इस विषय पर अच्छा बिजली बात मेरा मानना ​​है कि 'StringTraits ' पाश के लिए सीमा के अंदर सही ढंग से काम नहीं करेगा, 'स्थिरांक पर विचार ऑटो और एस 'पुनरावृत्ति ('के लिए (कॉन्स ऑटो और एस: तार) ...')। इसके बजाय कंटेनर की 'value_type' का उपयोग करना बेहतर विकल्प है। –

+0

@ श्री सी 64 'value_type' की आवश्यकता नहीं है। मैंने 'decltype' उपयोग को ठीक कर दिया है। – Angew

4

यहां एक सुंदर वाक्यविन्यास वाला एक है।

लक्ष्य @ Piotr के समाधान में अतिरिक्त () एस से छुटकारा पाने का लक्ष्य है।

बॉयलरप्लेट बहुत सारे:

template<bool b> 
struct static_if_t {}; 
template<bool b> 
struct static_else_if_t {}; 

struct static_unsolved_t {}; 

template<class Op> 
struct static_solved_t { 
    Op value; 
    template<class...Ts> 
    constexpr 
    decltype(auto) operator()(Ts&&...ts) { 
    return value(std::forward<Ts>(ts)...); 
    } 
    template<class Rhs> 
    constexpr 
    static_solved_t operator->*(Rhs&&)&&{ 
    return std::move(*this); 
    } 
}; 
template<class F> 
constexpr 
static_solved_t<std::decay_t<F>> static_solved(F&& f) { 
    return {std::forward<F>(f)}; 
} 

template<class F> 
constexpr 
auto operator->*(static_if_t<true>, F&& f) { 
    return static_solved(std::forward<F>(f)); 
} 
template<class F> 
constexpr 
static_unsolved_t operator->*(static_if_t<false>, F&&) { 
    return {}; 
} 
constexpr 
static_if_t<true> operator->*(static_unsolved_t, static_else_if_t<true>) { 
    return {}; 
} 
constexpr 
static_unsolved_t operator->*(static_unsolved_t, static_else_if_t<false>) { 
    return {}; 
} 

template<bool b> 
constexpr static_if_t<b> static_if{}; 

template<bool b> 
constexpr static_else_if_t<b> static_else_if{}; 

constexpr static_else_if_t<true> static_else{}; 

यहाँ क्या यह उपयोग के बिंदु पर की तरह लग रहा है:

template <typename ContainerOfStrings> 
void DoSomething(const ContainerOfStrings& strings) { 
    for (const auto & s : strings) 
    { 
    auto op = 
    static_if<std::is_same<typename ContainerOfStrings::value_type,CString>{}>->* 
    [&](auto&& s){ 
     // Use the CString interface 
    } 
    ->*static_else_if<std::is_same<typename ContainerOfStrings::value_type, std::cstring>{}>->* 
    [&](auto&& s){ 
     // Use the wstring interface 
    }; 
    op(s); // fails to compile if both of the above tests fail 
    } 
} 
static_else_if रों की एक असीमित श्रृंखला समर्थित साथ

यह आपको static_else (static_else) की असीमित श्रृंखला करने से रोकता है, उपरोक्त में static_else_if<true> के लिए केवल एक उपनाम है)।