2012-04-04 6 views
9

तो, मैं इस तरह एक समारोह लिखने के लिए कोशिश कर रहा था:टाइपफ़ोफ़ (std :: endl) टेम्पलेट पैरामीटर के रूप में नहीं हो सकता है?

void append_to_stream(std::ostream &stream) 
{ } 

template <typename T, typename... Args> 
void append_to_stream(std::ostream &stream, T first, Args&&... rest) 
{ 
    stream << first; 
    append_to_stream(stream, rest...); 
} 

और इसे पसंद फोन:

append_to_stream(stream, 
       std::endl, 
       std::endl); 

लेकिन यह काम नहीं करता। मुझे एक त्रुटि मिलती है जो फ़ंक्शन में 'बहुत अधिक तर्क' कहती है। मैंने इसे उस बिंदु तक सीमित कर दिया है, मुझे पता है कि std::endl दोषी है - शायद क्योंकि यह एक कार्य है। मैंने endl नामक एक स्ट्रक्चर घोषित करके इसे 'हल' करने में कामयाब रहा और इसके लिए <<operator परिभाषित किया ताकि यह आसानी से std::endl पर कॉल कर सके। यह काम करता है लेकिन विशेष रूप से अच्छा महसूस नहीं करता है। क्या टेम्पलेट तर्क के रूप में std :: endl को स्वीकार करना संभव नहीं है? समारोह अन्य प्रकार के लिए काम करता है।

संपादित करें:

src/log/sinks/file_sink.cpp:62:21: error: too many arguments to function ‘void log::sinks::append_to_stream(std::string&, Args&& ...) [with Args = {}, std::string = std::basic_string<char>]’ 

अद्यतन

सही टेम्पलेट तर्क @MooingDuck सुझाव दिया है कि निम्न प्रपत्र के एक समारोह इस्तेमाल किया जा सकता निकालना संकलक पाने के लिए कोशिश कर रहा है: यहाँ त्रुटि है

template<class e, class t, class a> 
    basic_ostream<e,t>&(*)(basic_ostream<e,t>&os) get_endl(basic_string<e,t,a>& s) 
    { 
return std::endl<e,t>; 
    } 

हालांकि, यह संकलित नहीं होता है।

त्रुटि:

src/log/sinks/file_sink.cpp:42:28: error: expected unqualified-id before ‘)’ token 
src/log/sinks/file_sink.cpp:42:53: error: expected initializer before ‘get_endl’ 

कोई भी विचार क्यों? इसे संकलित करने के लिए, मैंने using namespace std;

+0

होगा क्या संकलक आप उपयोग कर रहे हैं?आईआईआरसी कुछ कंप्यूटर्स को थोड़ी देर के लिए रिकर्सन के साथ परेशानी थी। – Flexo

+0

@awoodland मैं जीसीसी 4.6.2 का उपयोग कर रहा हूं :) – Max

+2

'std :: endl' कोई फ़ंक्शन नहीं है, यह एक टेम्पलेट है। –

उत्तर

14

std::endl एक टेम्पलेट है, फ़ंक्शन नहीं है, और संकलक उपयोग करने के लिए endl को हल नहीं कर सकता है।

प्रयास करें:

append_to_stream(std::cout, 
      std::endl<char, std::char_traits<char>>, 
      std::endl<char, std::char_traits<char>>); 

या, MooingDuck समाधान (सही):

template<class e, class t, class a> //string version 
auto get_endl(const std::basic_string<e, t, a>&) 
    -> decltype(&std::endl<e,t>) 
{ return std::endl<e,t>; } 

template<class e, class t> //stream version 
auto get_endl(const std::basic_ostream<e,t>&) 
    -> decltype(&std::endl<e,t>) 
{ return std::endl<e,t>; } 

int main() { 
    std::ostream& stream = std::cout; 
    append_to_stream(stream, 
       get_endl(stream), 
       get_endl(stream)); 
} 
+0

हां, यह पूरी तरह से काम करता है, धन्यवाद। Typedef templated कार्यों के लिए यह संभव नहीं है, है ना? :/ – Max

+0

@ मैक्स: आप एक फ़ंक्शन पर भी विचार कर सकते हैं। मुझे लगता है कि "टेम्पलेट <क्लास ई, क्लास टी> मूल_स्ट्रीम और (*) (basic_ostream और ओएस) get_endl (basic_ostream और एस) {वापसी std :: endl ;}' "ऐसा करना चाहिए। –

+0

@MooingDuck यह एक अच्छा विचार है, मुझे लगता है कि आप std :: endl के लिए टेम्पलेट तर्कों को कम करने के लिए स्ट्रीम का उपयोग करते हैं? समस्या यह है कि मैं जिस फ़ंक्शन का उपयोग करना चाहता हूं वह append_to_file (std :: string, ...) है जिसका अर्थ है कि तत्कालता के बिंदु पर मेरे पास स्ट्रीम ऑब्जेक्ट आसान नहीं है: /। कृपया मुझे बताएं कि क्या मैंने आपको गलत समझा है! – Max

4

बहुत:

template<class e, class t, class a> //string version 
std::basic_ostream<e, t>& (*get_endl(const std::basic_string<e, t, a>&)) 
    (std::basic_ostream<e, t>&) 
{ return std::endl<e,t>; } 

template<class e, class t> //stream version 
std::basic_ostream<e, t>& (*get_endl(const std::basic_ostream<e, t>&)) 
    (std::basic_ostream<e, t>&) 
{ return std::endl<e,t>; } 

int main() { 
    std::ostream& stream = std::cout; 
    append_to_stream(stream, 
       get_endl(stream), 
       get_endl(stream)); 
} 

यहाँ get_endl समाधान, द्वारा सी ++ 11 decltype सुविधा सरलीकृत है टेम्पलेट तर्क निर्दिष्ट करने या एक नया नया टेम्पलेट परिभाषित करने से आसान (!) अधिभार को हल कर रहा है कास्ट द्वारा

typedef std::ostream & (&omanip_t)(std::ostream &); 

append_to_stream(stream, 
       static_cast<omanip_t>(std::endl), 
       static_cast<omanip_t>(std::endl)); 

यह सभी manipulators के लिए काम, जबकि कुछ manipulators अलग ढंग से टेम्प्लेट किया जा सकता है, उदाहरण के लिए यदि उपयोगकर्ता द्वारा प्रदान की जाएगी।

इसके अलावा, आपको T first को किसी भी पूर्ण अग्रेषण या कॉन्स्ट संदर्भ द्वारा पास करना चाहिए। यह पहले आगे बढ़ने के लिए ज्यादा समझ नहीं आता है, और फिर मूल्य से गुजरता है। इसके अलावा, std::forward के लिए एक कॉल के बिना, rvalue तर्क मूल्य द्वारा पारित हो जाएगा ... बस मुहावरा निम्नलिखित, यह

template <typename T, typename... Args> 
void append_to_stream(std::ostream &stream, T &&first, Args&&... rest) 
{ 
    stream << std::forward<T>(first); 
    append_to_stream(stream, std::forward<Args>(rest) ...); 
} 

http://ideone.com/cw6Mc

+0

ऐसा लगता है कि std :: आगे (बाकी ...) संकलित नहीं करता है। जीसीसी का कहना है: 'std :: आगे()' के लिए कोई मिलान कॉल नहीं। मैं इसका मतलब यह समझता हूं कि बेस-केस काम नहीं करता है, जहां बाकी ... खाली है। यह इस तथ्य से समर्थित है कि यदि मैं अंतिम पैरामीटर को स्वीकार करने के लिए बेस-केस बदलता हूं, तो यह ठीक से संकलित करता है। उस ने कहा, क्या यह अधिमानतः rvalue और std :: आगे या सामान्य कॉन्स रेफ का उपयोग कर पारित करना है? अंतर क्या है? :) – Max

+0

@ मैक्स यिक्स, मुझे अग्रेषण मुहावरे गलत मिला! दोनों पैक एक ही 'द्वारा विस्तारित किया जाना चाहिए ...', लेकिन मैं यह नहीं बता सकता कि इस तरह से काम क्यों नहीं करता है। अद्यतन देखें। अंतर यह है कि 'कॉन्स्ट एंड' निर्दिष्ट करता है कि आप तर्क को संशोधित नहीं करेंगे, इसलिए यह संभवतः इस मामले में बेहतर है। ध्यान दें कि 'आगे' रावल संदर्भों पर निर्भर नहीं है और यदि आप इसे एक सादा स्थानीय चर नाम देते हैं तो सामान्य संशोधित lvalue ref द्वारा पारित किया जाएगा। – Potatoswatter