2013-02-22 20 views
5

पर लागू रूपांतरण नीचे दिया गया मेरा उदाहरण बताता है कि गैर-टेम्पलेट प्रकारों से टेम्पलेट प्रकारों के निहित रूपांतरण निर्बाध रूप से काम नहीं करेंगे क्योंकि उनमें केवल गैर-टेम्पलेट प्रकार शामिल हैं। क्या उन्हें फिर भी काम करने का कोई तरीका है?टेम्पलेट

उदाहरण:

struct point; 

template<unsigned d> struct vec { 
    vec() { } 
    // ... 
}; 

template<> struct vec<2> { 
    vec() { } 
    vec(const point& p) { /* ... */ } // Conversion constructor 
    // ... 
}; 

struct point { 
    operator vec<2>() { return vec<2>(/* ... */); } // Conversion operator 
}; 

template<unsigned d> vec<d> foo(vec<d> a, vec<d> b) { 
    return vec<d>(/* ... */); 
} 

template<unsigned d1, unsigned d2> 
vec<d1 + d2> bar(vec<d1> a, vec<d2> b) { 
    return vec<d1 + d2>(/* ... */); 
} 

int main(int argc, char** argv) { 
    point p1, p2; 
    vec<2> v2; 
    vec<3> v3; 
    foo(v2, p1); 
    foo(p2, v2); 
    foo(p1, p2); 
    bar(v3, p1); 
} 

वहाँ इस कोड को स्वत: परिवर्तित point से vec<2> को बताने के लिए एक तरीका है?

मैं जानता हूँ कि मैं foo और bar ओवरलोड कर सकते हैं point तर्क के लिए अनुमति देने के लिए, एक स्पष्ट रूपांतरण का उपयोग vec कार्यान्वयन के लिए सौंपने। लेकिन सभी पैरामीटर संयोजनों के लिए ऐसा करना कठिन हो जाएगा, खासकर ऐसे कई मानकों के साथ कार्यों के लिए। इसलिए मुझे समाधानों में दिलचस्पी नहीं है जहां मुझे प्रत्येक फ़ंक्शन के प्रत्येक पैरामीटर संयोजन के लिए कोड डुप्लिकेट करना होगा।

ऐसा प्रतीत होता है कि न तो रूपांतरण कन्स्ट्रक्टर और न ही कास्ट ऑपरेटर इसे प्राप्त करने के लिए पर्याप्त हैं। कम से कम मेरे जीसीसी 4.7.1 no matching function call की रिपोर्ट करता है, हालांकि यह ‘point’ is not derived from ‘vec<d>’ बताते हुए नोटिस में वांछित फ़ंक्शन का नाम देता है।

+0

कौन सी लाइन उस त्रुटि दे रही है? साथ ही, 'हस्ताक्षरित' एक सी ++ प्रकार नहीं है। –

+0

@ जेम्स: फंक्शन इनवोकेशन के साथ लाइनों के लिए त्रुटियों की सूचना दी गई है, हालांकि नोटिस कई अन्य लाइनों का भी उल्लेख करते हैं। ऊपर दिए गए कोड की प्रतिलिपि बनाने और संकलित करने के लिए स्वतंत्र महसूस करें, क्योंकि यह स्वयं निहित है। [सी ++ 11 मानक] की धारा 3.9.1 (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf) नाम 'हस्ताक्षरित' नाम, तो क्यों होगा यह सी ++ प्रकार नहीं है, सी के साथ साझा किया गया है? – MvG

+0

नहीं, यह 'हस्ताक्षरित लघु', 'हस्ताक्षरित लघु int',' हस्ताक्षरित int ',' हस्ताक्षरित लंबे int ', और' हस्ताक्षरित लंबे लंबे int 'को बिना हस्ताक्षर किए गए पूर्णांक प्रकारों के रूप में घोषित करता है। –

उत्तर

8

वहाँ क्योंकि समय था जब समारोह कॉल foo(v1,p1) संसाधित किया जाता है पर, point से vec<2> करने के लिए रूपांतरण प्राप्त करने के लिए कोई सीधा रास्ता है, एक समारोह foo कि दूसरा तर्क के रूप में एक vec<2> उम्मीद अभी तक मौजूद नहीं है। यह सिर्फ एक फ़ंक्शन टेम्पलेट है, और इसे foo(const vec<2> &,const vec<2> &) पर तुरंत चालू करने के लिए, इन सटीक तर्क प्रकारों के साथ एक फ़ंक्शन कॉल देना होगा।

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

इस सुलझाने के संदर्भ में, केवल एक चीज मैं के बारे में सोच सकते हैं अत्यधिक टेम्प्लेटेड रूपांतरण कार्यों बनाने के लिए है:

template <typename T> 
struct make_vec 
{ }; 

template <unsigned d> 
struct make_vec<vec<d>> 
{ 
    static constexpr unsigned dim = d; 
    using type = vec<dim>; 

    static const type &from(const type &v) 
    { return v; } 
}; 

template <> 
struct make_vec<point> 
{ 
    static constexpr unsigned dim = 2; 
    using type = vec<dim>; 

    static type from(const point &p) 
    { return type(p); } 
}; 

template <typename T> 
typename make_vec<typename std::decay<T>::type>::type make_vec_from(T&& arg) 
{ return make_vec<typename std::decay<T>::type>::from(std::forward<T>(arg)); } 

और फिर सामान्य टेम्पलेट्स (प्रकार के सभी प्रकार स्वीकार करने के रूप में foo और bar कार्यों को लागू,

namespace detail { 
    /* Your original implementation of foo. */ 
    template<unsigned d> vec<d> foo(vec<d>, vec<d>) { 
    return vec<d>(/* ... */); 
    } 
} 

/* Templated version of foo that calls the conversion functions (which do 
    nothing if the argument is already a vec<d>), and then calls the 
    foo() function defined above. */ 
template <typename T, typename... Ts> 
typename make_vec<typename std::decay<T>::type>::type foo(T&& arg, Ts&&... args) 
{ return detail::foo(make_vec_from(arg),make_vec_from(args)...); } 

के मामले में: केवल vec<d>, make_vec ऊपर परिभाषित का उपयोग कर vec<d> सही तरह) को दी प्रकार परिवर्तित करने के लिए नहींआपको रिटर्न प्रकार की गणना करने के लिए भी एक तरीका चाहिए, जो vec<d1+d2+d3...> है। इस के लिए, एक योग कैलकुलेटर की आवश्यकता है, यह भी टेम्प्लेट की गई:

template <typename... Ts> 
struct dsum { 
    static constexpr unsigned value = 0; 
}; 

template <typename T, typename... Ts> 
struct dsum<T,Ts...> { 
    static constexpr unsigned value = make_vec<typename std::decay<T>::type>::dim + dsum<Ts...>::value; 
}; 

फिर, bar() की वापसी प्रकार vec<dsum<T,Ts...>::value> है।

एक पूरी तरह से काम कर रहे उदाहरण यहाँ है: http://liveworkspace.org/code/nZJYu$11

ऐसा नहीं है आसान है, लेकिन यदि आप वास्तव में तर्कों की अत्यंत कई विभिन्न संयोजनों है इसके लायक हो सकता है।

+0

@ एमवीजी मैंने "पूर्ण कामकाजी उदाहरण" में संशोधन किया है। मेरा 'बार' कार्यान्वयन पहले संस्करण में गलत था। – jogojapan

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