2013-12-16 17 views
14

मेरे पास वर्तमान में map<int, std::wstring> है, लेकिन लचीलापन के लिए, मैं एक लैम्ब्डा अभिव्यक्ति असाइन करने में सक्षम होना चाहता हूं, std::wstring को मानचित्र में मान के रूप में लौटाना चाहता हूं।std :: टेम्पलेट पैरामीटर के रूप में कार्य

template <typename T> 
class ValueOrFunction 
{ 
private: 
    std::function<T()> m_func; 
public: 
    ValueOrFunction() : m_func(std::function<T()>()) {} 
    ValueOrFunction(std::function<T()> func) : m_func(func) {} 
    T operator()() { return m_func(); } 
    ValueOrFunction& operator= (const T& other) 
    { 
     m_func = [other]() -> T { return other; }; 
     return *this; 
    } 
}; 

और यह पसंद का उपयोग करें::

तो मैं इस टेम्पलेट श्रेणी का निर्माण

typedef ValueOrFunction<std::wstring> ConfigurationValue; 
std::map<int, ConfigurationValue> mymap; 

mymap[123] = ConfigurationValue([]() -> std::wstring { return L"test"; }); 
mymap[124] = L"blablabla"; 
std::wcout << mymap[123]().c_str() << std::endl; // outputs "test" 
std::wcout << mymap[124]().c_str() << std::endl; // outputs "blablabla" 

अब, मैं लैम्ब्डा लपेटकर के लिए निर्माता का उपयोग नहीं करना चाहते हैं, तो मैं करने का निर्णय लिया एक दूसरे असाइनमेंट ऑपरेटर std::function के लिए इस समय जोड़ने के लिए,:

ValueOrFunction& operator= (const std::function<T()>& other) 
{ 
    m_func = other; 
    return *this; 
} 

इस poi है एनटी जहां संकलक शिकायत शुरू करता है। लाइन mymap[124] = L"blablabla"; अचानक इस त्रुटि में परिणाम है:

error C2593: 'operator = is ambiguous'

IntelliSense कुछ अधिक जानकारी देता है:

more than one operator "=" matches these operands: function "ValueOrFunction::operator=(const std::function &other) [with T=std::wstring]" function "ValueOrFunction::operator=(const T &other) [with T=std::wstring]" operand types are: ConfigurationValue = const wchar_t [10] c:\projects\beta\CppTest\CppTest\CppTest.cpp 37 13 CppTest

तो, मेरे सवाल का, यही वजह है कि संकलक std::function<T()> और T के बीच भेद करने में सक्षम नहीं है? और मैं इसे कैसे ठीक कर सकता हूं?

उत्तर

12

मूल समस्या std::function एक लालची अंतर्निहित निर्माता कि कुछ भी परिवर्तित करने का प्रयास करेंगे, और केवल शरीर में संकलित करने के लिए असफल हो गई है। इसलिए यदि आप इसके साथ अधिभार करना चाहते हैं, तो विकल्प में कोई रूपांतरण की अनुमति नहीं दी जा सकती है, आपको उन चीज़ों को अक्षम करने की आवश्यकता है जो std::function ओवरलोड को कॉल करने के विकल्प में परिवर्तित कर सकते हैं।

सबसे आसान तकनीक टैग प्रेषण होगी। एक operator= कि लालची और सही अग्रेषण के लिए सेट किया गया है, तो मैन्युअल रूप से एक टैग के साथ एक assign विधि के लिए प्रेषण:

template<typename U> 
void operator=(U&&u){ 
    assign(std::forward<U>(u), std::is_convertible<U, std::wstring>()); 
} 
void assign(std::wstring, std::true_type /*assign_to_string*/); 
void assign(std::function<blah>, std::false_type /*assign_to_non_string*/); 

मूल रूप से हम मैन्युअल अधिभार संकल्प कर रहे हैं।

अधिक उन्नत तकनीकों: (शायद जरूरत नहीं)

एक और दृष्टिकोण लागू किया जा रहा तर्क पर SFINAE साथ std::function= सीमित करने के लिए किया जाएगा मान्य है, लेकिन है कि मेसियर है।

यदि आपके std::function के साथ प्रतिस्पर्धा करने वाले कई अलग-अलग प्रकार हैं तो आपको दुख से मैन्युअल रूप से उन सभी को प्रेषित करना होगा। इसे ठीक करने का तरीका यह जांचना है कि आपका प्रकार U कुछ भी नहीं है और परिणाम T पर परिवर्तनीय है, फिर उस पर प्रेषण टैग करें। वैकल्पिक शाखा में गैर-std::function अधिभार चिपकाएं, और बाकी सब कुछ के लिए सामान्य रूप से अधिक पारंपरिक ओवरलोडिंग होने दें।

वहाँ में है कि एक प्रकार दोनों std::wstring के लिए परिवर्तनीय और प्रतिदेय कुछ परिवर्तनीय लौटने T को समाप्त होता है इसके बाद के संस्करण मूल सरल समाधान की तुलना में अलग भार के लिए भेजा जा रहा है एक सूक्ष्म अंतर है, क्योंकि इस्तेमाल किया परीक्षण वास्तव में परस्पर अनन्य नहीं हैं। सी ++ ओवरलोडिंग के पूर्ण मैन्युअल अनुकरण के लिए (std::function एस मूर्खता के लिए सही) आपको बनाने की आवश्यकता है जो केस संदिग्ध है!

करने के लिए आखिरी उन्नत चीज auto का उपयोग करना होगा और अन्य = मान्य होने पर यह पता लगाने के लिए अन्य कोड की क्षमता में सुधार करने के लिए वापसी प्रकारों का पीछा करना होगा। व्यक्तिगत रूप से, मैं सी ++ 14 से पहले यह नहीं करूँगा, जो कि बिना किसी गंभीर पुस्तकालय कोड को लिख रहा था।

+0

इसे देखें [यहां] (http://ideone.com/XpOXMF) –

+0

मैं सोच रहा था कि क्या SFINAE समझ में आएगा, और मैंने इसे अत्यधिक जटिल के रूप में सुझाव देने का विकल्प नहीं चुना। अभ्यास के रूप में टैग प्रेषण यहां एक अच्छा साफ समाधान +1 है (हालांकि यह अधिक योग्य है) –

6

std::function और std::wstring दोनों में रूपांतरण ऑपरेटर हैं जो आपके द्वारा पारित शाब्दिक चौड़ी स्ट्रिंग ले सकते हैं। दोनों मामलों में रूपांतरण उपयोगकर्ता परिभाषित होते हैं और इस प्रकार रूपांतरण अनुक्रम एक ही प्राथमिकता लेता है, जिससे अस्पष्टता आती है। यह त्रुटि का मूल कारण है।

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