2012-10-28 20 views
10

मान लें:अप्रत्याशित अधिभार कोड निम्नलिखित जब समारोह variadic टेम्पलेट इन्स्टेन्शियशन से कहा जाता है कहा जाता है

#include <iostream> 

template<typename... T> 
void foo(const T &...); 

template<unsigned N> 
void foo(const char (&)[N]) 
{ 
    std::cout << "char(&)[N]" << std::endl; 
} 

void foo(const char *) 
{ 
    std::cout << "const char *" << std::endl; 
} 

template<typename T> 
void foo(const T &) 
{ 
    std::cout << "Single" << std::endl; 
} 

template<typename First, typename... T> 
void foo(const First & first, const T &... rest) 
{ 
    std::cout << "Generic + " << sizeof...(T) << std::endl; 
    foo(first); 
    foo(rest...); 
} 

int main() 
{ 
    const char * c = "asdf"; 
    char a[] = {'a', 'b', 'c', 'd'}; 
    foo('f', c, a, 1); 
    foo(a); 
} 

The output is:

Generic + 3 
Single    // fine; 'f' is `char` -> generic 
Generic + 2 
const char *  // fine; c is `const char *` 
Generic + 1 
const char *  // (!) not fine 
Single 
char(&)[N]   // fine; a is char[4] 

आखिरी कॉल - foo(a), जहां achar[4] है - संस्करण मैं कॉल उम्मीद - template<unsigned N> void foo(const char (&)[N])। लेकिन foo के चरणीय टेम्पलेट का तात्कालिकता क्यों नहीं है foo(const char (&)[N] पर कॉल करें, लेकिन इसके बजाय foo(const char *) पर कॉल करें? यदि कोई चार सरणी अधिभार नहीं था, तो इसकी अपेक्षा की जानी चाहिए - लेकिन यह क्यों हो रहा है? const First & कैप्चर सरणी प्रकार ठीक से नहीं होना चाहिए?

इसके अलावा, जेनेरिक वैरिएड संस्करण को पारित किए गए सरणी के साथ ठीक तरह से काम करने का सबसे आसान तरीका क्या होगा? माथीउ एम


के रूप में टिप्पणी में देखा यह समस्या शायद variadic टेम्पलेट्स के कारण नहीं है, लेकिन indirection द्वारा:

#include <iostream> 

template <unsigned N> 
void foo(const char (&)[N]) 
{ 
    std::cout << "char(&)[N]" << std::endl; 
} 

void foo(const char *) 
{ 
    std::cout << "const char *" << std::endl; 
} 

template <typename T> 
void goo(T const& t) { 
    foo(t); 
} 

int main() 
{ 
    char a[] = {'a', 'b', 'c', 'd'}; 
    foo(a); 
    goo(a); 
} 
 
    char(&)[N] 
    const char * 

उन्होंने यह भी कहा है कि यह संकलक हो सकता है बग - हालांकि कोड क्लेंग 3.2 देव, जी ++ 4.6 और 4.7 दोनों में बिल्कुल वही परिणाम उत्पन्न करता है।

आर Martinho फर्नांडीस ने कहा कि const char a[] करने के लिए पिछले टुकड़ा में बदल रहा है a के प्रकार कोड उपज const char * बनाता है दो बार।

+1

क्यों '// ठीक है; "afas" const const * 'है? यह नहीं! http://ideone.com/4KewDe –

+0

@ आर। मार्टिन्हो फर्नांडीस, तय। – Griwes

+2

मैंने समस्या को और कम करने में कामयाब रहे [यहां] (http://liveworkspace.org/code/72b3963b4f0c2d00592b4ce00f08fc82)। स्पष्ट रूप से संकेत इस मुद्दे का कारण बन रहा है और इसके साथ भिन्नता का कोई लेना-देना नहीं है। फिर भी एक संभावित स्पष्टीकरण नहीं मिला है ... यह निश्चित रूप से मेरे लिए एक कंपाइलर बग की तरह दिखता है। –

उत्तर

5

मुझे लगता है कि मैं दूसरे खंड का उत्तर दे सकता हूं: इसे कैसे ठीक करें? मुझे यकीन नहीं है कि मुझे सही जवाब मिल गया है क्योंकि एक स्ट्रिंग शब्दकोष उत्तीर्ण करने का मामला, मेरी राय में, अभी भी गलत परिणाम है। फिक्स के लिए मूल विचार यह है कि T const& के लिए सही प्रकार का अनुमान लगाया गया है, इसके बजाय सही अग्रेषण का उपयोग करना है। एक सरणी के साथ T const& का उपयोग क्यों करना सरणी को क्षय का कारण बनता है, हालांकि, मुझे काफी नहीं लगता है।

सही आगे का उपयोग करना, इसका मतलब है कि यह कार्य करने का कार्य एक आदर्श मैच है और कुछ विशेषज्ञता वास्तव में कुछ रूपांतरण करते हैं, कम से कम const जोड़ते हैं। इस प्रकार, एक अलग नाम का उपयोग करना आवश्यक है। कुल मिलाकर, यह इस तरह दिखता है:

#include <iostream> 
#include <utility> 

void foo() 
{ 
} 

template<unsigned N> 
void special(const char (&)[N]) 
{ 
    std::cout << "char(&)[" << N << "]" << '\n'; 
} 

void special(const char *) 
{ 
    std::cout << "const char *" << '\n'; 
} 

template<typename T> 
void special(const T &) 
{ 
    std::cout << "Single" << '\n'; 
} 

template<typename First, typename... T> 
void foo(First&& first, T&&... rest) 
{ 
    std::cout << "Generic + " << sizeof...(T) << '\n'; 
    special(std::forward<First>(first)); 
    foo(std::forward<T>(rest)...); 
} 

int main() 
{ 
    char const* c("foo"); 
    char a[] = {'a', 'b', 'c', 'd'}; 
    foo('f', "afas", a, c, 1); 
    foo(a); 
} 
संबंधित मुद्दे