2016-10-09 14 views
5

को तर्क की कल्पना मैं इस struct मिल गया है:टाइप- केवल टेम्पलेट लैम्ब्डा

struct Foo { 
    operator int() { 
     return 11; 
    } 
    operator unsigned int() { 
     return 22; 
    } 
} foo; 

जब यह struct किसी पूर्णांक पर casted है, यह रिटर्न 11 है, लेकिन जब एक अहस्ताक्षरित पूर्णांक के लिए casted, यह 22 देता है।

सामान्य कार्यों का उपयोग करना, मैं टेम्पलेट्स इस्तेमाल कर सकते हैं और एक गेटर समारोह का चयन करने के:

template<typename T> 
T get() { 
    return (T)foo; 
} 

अब, जब get<int>() की तरह इस कार्यप्रणाली को कॉल यह 11 वापसी होगी , लेकिन इसे get<unsigned int>() की तरह कॉल करते समय यह 22 वापस आ जाएगा।

सब कुछ ठीक अब तक, जब मैं बजाय lambdas इस्तेमाल करने की कोशिश: जब लैम्ब्डा lambda(0) के रूप में यह रिटर्न 11 आह्वान करने और lambda(0U) रिटर्न 22 के रूप में यह बुला अब

auto lambda=[](auto type) { 
    return (decltype(type))foo; 
}; 

यह सही ढंग से काम करता है, हालांकि 'हैकी', लेकिन इस प्रकार का एक उदाहरण उपयोग करने की आवश्यकता है, जो बड़े प्रकार के साथ आदर्श नहीं होगा। तो एक और तरह से ऊपर स्प्रिंग्स, यहां तक ​​कि 'hackier', इस लक्ष्य को हासिल करने के लिए:

auto lambda=[](auto* typePointer) { 
    return (decltype(*typePointer))foo; 
}; 

अब lambda((int*)NULL) रिटर्न 11 के रूप में यह बुला लेकिन lambda((unsigned int*)NULL) रिटर्न 22 के रूप में यह मांग की। आपने देखा के रूप में हो सकता है इस बल्कि वर्बोज़ और 'hacky' है, इसलिए मैं एक और अधिक सरल और पारंपरिक विधि की कोशिश की:

auto lambda=[]<typename T>() { 
    return (T)foo; 
}; 

पहले तो मैंने सोचा कि यह संकलन नहीं होगा, के बाद से मैं इस वाक्य रचना नहीं देखा है कहीं भी, लेकिन यह संकलित करता है (कम से कम जीसीसी के साथ)। हालांकि, जब यह कॉल करने के लिए कोशिश कर रहा है, त्रुटियों दिखाई देते हैं:

lambda(); 


testlambda.cpp: In function ‘int main()’: 
testlambda.cpp:25:9: error: no match for call to ‘(main()::<lambda()>)()’ 
    lambda(); 
     ^
testlambda.cpp:22:29: note: candidate: template<class T> main()::<lambda()> 
    auto lambda=[]<typename T>() { 
          ^
testlambda.cpp:22:29: note: template argument deduction/substitution failed: 
testlambda.cpp:25:9: note: couldn't deduce template parameter ‘T’ 
    lambda(); 
     ^

जैसा कि आप देख सकते हैं, एक उम्मीदवार template<class T> main()::<lambda()> है, लेकिन इस संकलन नहीं करता है या तो:

lambda<int>()->error: expected primary-expression before ‘int’

तो, मेरा सवाल है: ऐसा करने का आधिकारिक, मानक-अनुपालन तरीका क्या है, यदि कोई है? मुझे उम्मीद है कि पॉइंटर हैक एकमात्र तरीका नहीं है। असली कोड में उपयोग करने के लिए यह वास्तव में बेकार लगता है।

मैं अपने कंपाइलर के रूप में जी ++ (जीसीसी 5.4.0) का उपयोग कर रहा हूं। मैं सी ++ 14 मानक का उपयोग भी कर रहा हूं जैसे -std=c++14

auto lambda = [](auto type) { 
    return static_cast<typename decltype(type)::type>(foo); 
}; 

या

auto lambda = [](auto type) -> typename decltype(type)::type { 
    return foo; 
}; 

और ऐसा लगता है फोन:

template <class T> struct tag_t { using type = T; }; 
template <class T> 
constexpr tag_t<T> tag{}; 

आप अपने लैम्ब्डा की तरह लिख सकते हैं:

+1

अक्सर यह 'टेम्पलेट स्ट्रक्चर टाइप {typedef टी प्रकार के रूप में किया जाता है; }; '। इसे पास करें और 'टाइपनाम डेमटाइप (पैरा) :: टाइप' का उपयोग करें। –

उत्तर

7

आप एक खाली टैग प्रकार के एक चर टेम्पलेट पारित कर सकते हैं :

lambda(tag<int>); // 11 
lambda(tag<unsigned>); // 22 
+0

वाह। यह वास्तव में कारगर है। यह वास्तव में एक अच्छा समाधान है, भले ही एक तर्क, जो कि वास्तव में मूल्य नहीं है, फिर भी इसे पारित करने की आवश्यकता है। Templated 'constexpr's की अवधारणा मेरे लिए कुछ नया है, मुझे इसके बारे में पढ़ना होगा। और यह क्यों है कि इसे 'टाइपनाम' की आवश्यकता है ताकि इसे काम कर सकें? 'टेम्पलेट' को हल करते समय संकलक नहीं होना चाहिए कि 'decltype (type) :: type' वास्तव में एक प्रकार है और कोई मान नहीं है? बहुत धन्यवाद, यह मेरी समस्या को अच्छी तरह से हल करता है। – negamartin

+1

@negamartin [यह सवाल] देखें (http://stackoverflow.com/q/610245/2069064) – Barry

+0

ओह, मैं देखता हूं। टाइप करने में थोड़ा लंबा, लेकिन 'उपयोग' को छोटे नाम पर उपनाम करने में सक्षम होना चाहिए। – negamartin

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