दिलचस्प पोस्ट
SQL सर्वर – INSERT के बाद मूल्य लौटें क्या जावा में कंस्ट्रक्टर कोड चलाने से पहले खेले जाने वाले फ़ील्ड शुरू होते हैं? इनलाइन ब्लॉक तत्वों के बीच की जगह को कैसे निकालना है? जावा: किसी दूसरे वर्ग से तरीकों तक कैसे पहुंचें क्या R_X86_64_32S और R_X86_64_64 पुनर्स्थापन मतलब क्या है? PhpMailer और PHP का उपयोग कर फॉर्म से फाइल अटैचमेंट भेजें एकाधिक मॉडल एडमिन / Django व्यवस्थापक में एक ही मॉडल के लिए विचार आप VBA कोड के समय का परीक्षण कैसे करते हैं? एंड्रॉइड – पीआईडी ​​का उपयोग करके प्रोसेसनाम या पैकेज कैसे प्राप्त करें? एक पीएचपी फ़ाइल में सीधी पहुंच रोकें PHP + कर्ल, HTTP पोस्ट नमूना कोड? Android पर स्क्रीन रोटेशन को रोकें कैसे (सचमुच) सभी जीसीसी की चेतावनियां चालू करें? कैसे एक numpy सरणी में एक अतिरिक्त कॉलम जोड़ने के लिए क्या DOMAttrModified के लिए एक विकल्प है जो वेबकिट में काम करेगा

सुंदर मुद्रित std :: tuple

यह सुंदर प्रिंटिंग एसटीएल कंटेनरों पर मेरे पिछले प्रश्न के लिए अनुवर्ती है, जिसके लिए हमने एक बहुत सुंदर और पूरी तरह से सामान्य समाधान विकसित करने में कामयाब रहे।


इस अगले चरण में, मैं std::tuple<Args...> लिए बहुत-मुद्रण शामिल करना चाहता std::tuple<Args...> , variadic टेम्पलेट्स का उपयोग कर रहा है (इसलिए यह कड़ाई से सी ++ 11 है)। std::pair<S,T> , मैं बस कहता हूँ

 std::ostream & operator<<(std::ostream & o, const std::pair<S,T> & p) { return o << "(" << p.first << ", " << p.second << ")"; } 

एक ट्यूपल छपाई करने के लिए समान निर्माण क्या है?

मैंने टेम्पलेट तर्क स्टैक अनपैकिंग के विभिन्न बिट्स की कोशिश की है, इंडेक्स को पास कर रहा है और SFINAE का उपयोग करके पता चलता है कि जब मैं अंतिम तत्व पर हूं, लेकिन कोई सफलता नहीं मिली है। मैं आपको अपने टूटे कोड के साथ बोझ नहीं करेगा; समस्या का वर्णन उम्मीद है कि सीधे-सीधे पर्याप्त है मूलतः, मुझे निम्न व्यवहार चाहिए:

 auto a = std::make_tuple(5, "Hello", -0.1); std::cout << a << std::endl; // prints: (5, "Hello", -0.1) 

पिछले प्रश्न के अनुसार सामान्यता के समान स्तर को शामिल करने के लिए बोनस अंक (char / wchar_t, जोड़ी सीमांकक)!

वेब के समाधान से एकत्रित समाधान "सुंदर मुद्रित std :: tuple"

याय, सूचकांक ~

 namespace aux{ template<std::size_t...> struct seq{}; template<std::size_t N, std::size_t... Is> struct gen_seq : gen_seq<N-1, N-1, Is...>{}; template<std::size_t... Is> struct gen_seq<0, Is...> : seq<Is...>{}; template<class Ch, class Tr, class Tuple, std::size_t... Is> void print_tuple(std::basic_ostream<Ch,Tr>& os, Tuple const& t, seq<Is...>){ using swallow = int[]; (void)swallow{0, (void(os << (Is == 0? "" : ", ") << std::get<Is>(t)), 0)...}; } } // aux:: template<class Ch, class Tr, class... Args> auto operator<<(std::basic_ostream<Ch, Tr>& os, std::tuple<Args...> const& t) -> std::basic_ostream<Ch, Tr>& { os << "("; aux::print_tuple(os, t, aux::gen_seq<sizeof...(Args)>()); return os << ")"; } 

आइडियान पर लाइव उदाहरण


सीमांकक सामान के लिए, बस इन आंशिक विशेषज्ञों को जोड़ें:

 // Delimiters for tuple template<class... Args> struct delimiters<std::tuple<Args...>, char> { static const delimiters_values<char> values; }; template<class... Args> const delimiters_values<char> delimiters<std::tuple<Args...>, char>::values = { "(", ", ", ")" }; template<class... Args> struct delimiters<std::tuple<Args...>, wchar_t> { static const delimiters_values<wchar_t> values; }; template<class... Args> const delimiters_values<wchar_t> delimiters<std::tuple<Args...>, wchar_t>::values = { L"(", L", ", L")" }; 

और operator<< और print_tuple तदनुसार print_tuple :

 template<class Ch, class Tr, class... Args> auto operator<<(std::basic_ostream<Ch, Tr>& os, std::tuple<Args...> const& t) -> std::basic_ostream<Ch, Tr>& { typedef std::tuple<Args...> tuple_t; if(delimiters<tuple_t, Ch>::values.prefix != 0) os << delimiters<tuple_t,char>::values.prefix; print_tuple(os, t, aux::gen_seq<sizeof...(Args)>()); if(delimiters<tuple_t, Ch>::values.postfix != 0) os << delimiters<tuple_t,char>::values.postfix; return os; } 

तथा

 template<class Ch, class Tr, class Tuple, std::size_t... Is> void print_tuple(std::basic_ostream<Ch, Tr>& os, Tuple const& t, seq<Is...>){ using swallow = int[]; char const* delim = delimiters<Tuple, Ch>::values.delimiter; if(!delim) delim = ""; (void)swallow{0, (void(os << (Is == 0? "" : delim) << std::get<Is>(t)), 0)...}; } 

मुझे सी ++ 11 (जीसीसी 4.7) में यह कार्य ठीक मिला है। मुझे यकीन है कि मैंने कुछ नुकसान नहीं किए हैं लेकिन मुझे लगता है कि कोड पढ़ने में आसान है और जटिल नहीं है। केवल एक चीज जो अजीब हो सकती है वह "गार्ड" संरचना ट्यूपल_प्रिंटर है जो सुनिश्चित करती है कि हम अंतिम तत्व कब तक पहुंच जाएंगे। दूसरी अजीब बात यह हो सकती है कि आकार … (प्रकार) प्रकार प्रकार प्रकारों में संख्याओं को वापस लौटाते हैं। यह अंतिम तत्व का सूचक निर्धारित करने के लिए उपयोग किया जाता है (आकार … (प्रकार) – 1)।

 template<typename Type, unsigned N, unsigned Last> struct tuple_printer { static void print(std::ostream& out, const Type& value) { out << std::get<N>(value) << ", "; tuple_printer<Type, N + 1, Last>::print(out, value); } }; template<typename Type, unsigned N> struct tuple_printer<Type, N, N> { static void print(std::ostream& out, const Type& value) { out << std::get<N>(value); } }; template<typename... Types> std::ostream& operator<<(std::ostream& out, const std::tuple<Types...>& value) { out << "("; tuple_printer<std::tuple<Types...>, 0, sizeof...(Types) - 1>::print(out, value); out << ")"; return out; } 

मुझे आश्चर्य है कि cppreference पर कार्यान्वयन पहले से ही यहां पोस्ट नहीं किया गया है, इसलिए मैं भावी पीढ़ी के लिए यह करूँगा यह std::tuple_cat लिए डॉक्टर में छिपा हुआ है, इसलिए इसे std::tuple_cat आसान नहीं है। यह यहां कुछ अन्य समाधानों की तरह गार्ड संरक्षक का उपयोग करता है, लेकिन मुझे लगता है कि उनका अंततः सरल और आसान-पालन करना है

 #include <iostream> #include <tuple> #include <string> // helper function to print a tuple of any size template<class Tuple, std::size_t N> struct TuplePrinter { static void print(const Tuple& t) { TuplePrinter<Tuple, N-1>::print(t); std::cout << ", " << std::get<N-1>(t); } }; template<class Tuple> struct TuplePrinter<Tuple, 1> { static void print(const Tuple& t) { std::cout << std::get<0>(t); } }; template<class... Args> void print(const std::tuple<Args...>& t) { std::cout << "("; TuplePrinter<decltype(t), sizeof...(Args)>::print(t); std::cout << ")\n"; } // end helper function 

और एक परीक्षा:

 int main() { std::tuple<int, std::string, float> t1(10, "Test", 3.14); int n = 7; auto t2 = std::tuple_cat(t1, std::make_pair("Foo", "bar"), t1, std::tie(n)); n = 10; print(t2); } 

आउटपुट:

(10, टेस्ट, 3.14, फ़ू, बार, 10, टेस्ट, 3.14, 10)

लाइव डेमो

सी ++ 17 में हम फ़ोल्ड एक्सप्रेशंस का फायदा उठाकर थोड़ा कम कोड के साथ इसे पूरा कर सकते हैं, विशेषकर एक अनारी बाएं गुना:

 template<class TupType, size_t... I> void print(const TupType& _tup, std::index_sequence<I...>) { std::cout << "("; (..., (std::cout << (I == 0? "" : ", ") << std::get<I>(_tup))); std::cout << ")\n"; } template<class... T> void print (const std::tuple<T...>& _tup) { print(_tup, std::make_index_sequence<sizeof...(T)>()); } 

लाइव डेमो आउटपुट:

(5, हैलो, -0.1)

दिया हुआ

 auto a = std::make_tuple(5, "Hello", -0.1); print(a); 

व्याख्या

हमारा अनारी बायां गुना फार्म का है

 ... op pack 

जहां हमारे परिदृश्य में op अल्पविराम ऑपरेटर है, और pack एक अप्रत्याशित संदर्भ में हमारे ट्यूपल युक्त अभिव्यक्ति है जैसे:

 (..., (std::cout << std::get<I>(myTuple)) 

तो अगर मेरे पास ऐसा ट्यूपल है तो:

 auto myTuple = std::make_tuple(5, "Hello", -0.1); 

और एक std::integer_sequence जिसका मूल्य एक गैर-प्रकार टेम्पलेट द्वारा निर्दिष्ट किया गया है (ऊपर कोड देखें)

 size_t... I 

फिर अभिव्यक्ति

 (..., (std::cout << std::get<I>(myTuple)) 

इसमें विस्तार हो जाता है

 ((std::cout << std::get<0>(myTuple)), (std::cout << std::get<1>(myTuple))), (std::cout << std::get<2>(myTuple)); 

कौन प्रिंट करेगा

5Hello-0.1

जो सकल है, इसलिए हमें पहले से मुद्रित किए जाने के लिए अल्पविराम विभाजक को जोड़ने के लिए कुछ और चीजें करने की आवश्यकता है, जब तक कि यह पहला तत्व न हो।

यह पूरा करने के लिए, हम " ," यदि वर्तमान सूचकांक पहले नहीं है, तो (I == 0? "" : ", ") भाग * प्रिंट करने के लिए गुना अभिव्यक्ति के pack भाग को संशोधित करें: *

 (..., (std::cout << (I == 0? "" : ", ") << std::get<I>(_tup))); 

और अब हम मिलेंगे

5, हैलो, -0.1

जो अच्छा दिखता है (नोट: मुझे इस उत्तर के समान उत्पादन चाहिए)

* नोट: आप विभिन्न तरीकों से अल्पसंख्यक जुदाई कर सकते हैं। मैंने शुरू में std::tuple_size<TupType>::value - 1 खिलाफ परीक्षण करने से पहले std::tuple_size<TupType>::value - 1 से पहले जोड़ा था, लेकिन यह बहुत लंबा था, इसलिए मैं इसके बजाय sizeof...(I) - 1 खिलाफ परीक्षण किया, लेकिन अंत में मैंने ज़ीओ की नकल की और हमने जो कुछ हासिल किया है उसके साथ समाप्त हुआ।

उदाहरण के आधार पर सी ++ प्रोग्रामिंग लैंग्वेज द्वारा बर्जनी स्ट्राउट्रुप, पृष्ठ 817 :

 #include <tuple> #include <iostream> #include <string> #include <type_traits> template<size_t N> struct print_tuple{ template<typename... T>static typename std::enable_if<(N<sizeof...(T))>::type print(std::ostream& os, const std::tuple<T...>& t) { char quote = (std::is_convertible<decltype(std::get<N>(t)), std::string>::value) ? '"' : 0; os << ", " << quote << std::get<N>(t) << quote; print_tuple<N+1>::print(os,t); } template<typename... T>static typename std::enable_if<!(N<sizeof...(T))>::type print(std::ostream&, const std::tuple<T...>&) { } }; std::ostream& operator<< (std::ostream& os, const std::tuple<>&) { return os << "()"; } template<typename T0, typename ...T> std::ostream& operator<<(std::ostream& os, const std::tuple<T0, T...>& t){ char quote = (std::is_convertible<T0, std::string>::value) ? '"' : 0; os << '(' << quote << std::get<0>(t) << quote; print_tuple<1>::print(os,t); return os << ')'; } int main(){ std::tuple<> a; auto b = std::make_tuple("One meatball"); std::tuple<int,double,std::string> c(1,1.2,"Tail!"); std::cout << a << std::endl; std::cout << b << std::endl; std::cout << c << std::endl; } 

आउटपुट:

 () ("One meatball") (1, 1.2, "Tail!") 

और यहां एक और क्रियान्वयन है:

https://github.com/galaxyeye/atlas/blob/master/atlas/io/tuple.h

परीक्षण कोड के साथ:

https://github.com/galaxyeye/atlas/blob/master/libs/serialization/test/tuple.cpp

का आनंद लें 🙂

टोनी ऑल्ससन के समान, एक और एक, जिसमें खाली ट्यूपल के लिए विशेषज्ञता शामिल है, जैसा कि केरक एसबी द्वारा सुझाए गए

 #include <tuple> #include <iostream> template<class Ch, class Tr, size_t I, typename... TS> struct tuple_printer { static void print(std::basic_ostream<Ch,Tr> & out, const std::tuple<TS...> & t) { tuple_printer<Ch, Tr, I-1, TS...>::print(out, t); if (I < sizeof...(TS)) out << ","; out << std::get<I>(t); } }; template<class Ch, class Tr, typename... TS> struct tuple_printer<Ch, Tr, 0, TS...> { static void print(std::basic_ostream<Ch,Tr> & out, const std::tuple<TS...> & t) { out << std::get<0>(t); } }; template<class Ch, class Tr, typename... TS> struct tuple_printer<Ch, Tr, -1, TS...> { static void print(std::basic_ostream<Ch,Tr> & out, const std::tuple<TS...> & t) {} }; template<class Ch, class Tr, typename... TS> std::ostream & operator<<(std::basic_ostream<Ch,Tr> & out, const std::tuple<TS...> & t) { out << "("; tuple_printer<Ch, Tr, sizeof...(TS) - 1, TS...>::print(out, t); return out << ")"; }