2011-04-04 16 views
10

पर संदर्भ पास करना मैं एक इवेंट लाइब्रेरी पर काम कर रहा हूं और मुझे वैराडिक टेम्पलेट्स के साथ समस्या का सामना करना पड़ रहा है।वैराडिक टेम्पलेट्स

सभी तथ्य को छोड़कर बहुत अच्छा है कि मैं पैरामीटर के रूप में संदर्भ पारित नहीं हो सकता काम कर रहा है ...

यहाँ एक बहुत ही सरल उदाहरण मेरी समस्या का पर्दाफाश करने में लिखा है।

struct DelayedSignal 
{ 
    ~DelayedSignal() 
    { std::cout << "~DelayedSignal CLOSE" << std::endl; } 

    template<class C, class... Args> 
    DelayedSignal (void(C::*func)(Args...), C& obj) 
    { std::cout << "DelayedSignal INIT - 03 - pointer to method & pointer to class instance (Arg num: " << sizeof...(Args) << ")" << std::endl; } 

    template<class C, class... Args> 
    DelayedSignal (void(C::*func)(Args...), C& obj, Args... args) 
    { 
     std::cout << "DelayedSignal INIT - 04 - pointer to method & pointer to class instance & arguments (Arg num: " << sizeof...(Args) << ")" << std::endl; 
    } 
}; 

template<class... ArgsBis> 
struct DelayedSignal_DebugHelper 
{ 
    ~DelayedSignal_DebugHelper() 
    { std::cout << "~DelayedSignal_DebugHelper CLOSE" << std::endl; } 

    template<class C, class... Args> 
    DelayedSignal_DebugHelper (void(C::*func)(Args...), C& obj) 
    { std::cout << "DelayedSignal_DebugHelper INIT - 03 - pointer to method & pointer to class instance (Arg num: " << sizeof...(Args) << ")" << std::endl; } 

    template<class C, class... Args> 
    DelayedSignal_DebugHelper (void(C::*func)(Args...), C& obj, ArgsBis... args) // Need to use ArgsBis instead of Args to make it work 
    { 
     std::cout << "DelayedSignal_DebugHelper INIT - 04 - pointer to method & pointer to class instance & arguments (Arg num: " << sizeof...(Args) << ")" << std::endl; 
    } 
}; 


template < class Tr, class... Args > 
struct Signal 
{ 
    void fire (Args... args) { std::cout << "Signal::fire::" << sizeof...(Args) << std::endl; } 
}; 

struct Klass {}; 


int main() 
{ 
    std::string str1("Blop"); // Will be used as reference 
    Klass k;     // Will be used as reference 

    Signal<void, Klass&> signal_01; 
    Signal<void, std::string&> signal_02; 

    std::cout << "====== DelayedSignal :: needed for production purpose ===============" << std::endl; 

    // OK 
    DelayedSignal test01(&Signal<void, std::string&>::fire, signal_02); 
    // HERE IS THE PROBLEM 
    //DelayedSignal test02(&Signal<void, std::string&>::fire, signal_02, str1); 

    // OK 
    DelayedSignal test03(&Signal<void, Klass&>::fire, signal_01); 
    // HERE IS THE PROBLEM 
    //DelayedSignal test04(&Signal<void, Klass&>::fire, signal_01, k); 

    std::cout << "====== DelayedSignal_DebugHelper :: used only for debug purpose ======" << std::endl; 

    // OK 
    DelayedSignal_DebugHelper<std::string&> test05(&Signal<void, std::string&>::fire, signal_02); 
    // OK 
    DelayedSignal_DebugHelper<std::string&> test06(&Signal<void, std::string&>::fire, signal_02, str1); 

    // OK 
    DelayedSignal_DebugHelper<Klass&> test07(&Signal<void, Klass&>::fire, signal_01); 
    // OK 
    DelayedSignal_DebugHelper<Klass&> test08(&Signal<void, Klass&>::fire, signal_01, k); 

    return 1; 
} 

मैं एक एकल std :: सूची उदाहरण में सभी DelayedSignal उदाहरणों रजिस्टर के रूप में मैं वर्ग पर ही टेम्पलेट का उपयोग कर से बचने के लिए चाहते हैं, और यही कारण है कि मैं बजाय कंस्ट्रक्टर्स पर टेम्पलेट का उपयोग है। मैं सभी विलम्बित सिग्नल के लिए शुद्ध वर्चुअल क्लास का उपयोग कर सकता हूं और वर्चुअल क्लास को std :: सूची में पॉइंटर्स पंजीकृत कर सकता हूं लेकिन मुझे लगता है कि आभासी तरीकों के उपयोग को कम करना सबसे अच्छा है और मैं वास्तव में इस समस्या से चिंतित हूं ...

जैसा कि आप इस उदाहरण में देख सकते हैं, test02 और test04 वापसी त्रुटियों को सक्रिय करते हैं। DelayedSignal_DebugHelper देरी सिग्नल के लगभग समान है, इस तथ्य को छोड़कर कि यह ArgsBis (विधि टेम्पलेट तर्क) के बजाय अंतिम कन्स्ट्रक्टर पर ArgsBis (एक क्लास टेम्पलेट तर्क) का उपयोग करता है, अन्यथा यह काम नहीं करता है (देरी से सिग्नल के साथ)। void(C::*func)(Args...) पर Args स्वीकार किए जाते हैं लेकिन ArgsBis... args के साथ नहीं है, इस तथ्य के बावजूद कि वे एक ही निर्माता घोषणा में हैं।

जहां तक ​​मुझे पता है, संदर्भों के बिना कोई समस्या नहीं है (उदाहरण के लिए DelayedSignal test04(&Signal<void, Klass>::fire, signal_01, k);) या एकाधिक पैरामीटर (या कोई नहीं) जब तक कोई संदर्भ नहीं है।

क्या इस समस्या को ठीक करने के लिए वैसे भी है?

धन्यवाद।

+0

संकलक संस्करण है? –

+0

@ वॉल्के क्या आपको इसे C++ 0x से टैग नहीं करना चाहिए? मैंने आपके समाधान को संकलित करने की कोशिश की और यह सोच रहा था कि यह विजुअल स्टूडियो 2011 में क्यों काम नहीं कर रहा था; विविध टेम्पलेट्स देखने के बाद, मुझे अभी एहसास हुआ कि यदि खोज सही है, तो यह एक नई सुविधा है।वैसे भी कंपाइलर्स वास्तव में इसका समर्थन करते हैं? – leetNightshade

+0

@ स्लेट: जोड़ा गया टैग। यह सुविधा संस्करण 4.3 के बाद g ++ द्वारा समर्थित है - अधिक जानकारी के लिए यह लिंक देखें: http://gcc.gnu.org/projects/cxx0x.html – TonyK

उत्तर

1

हावर्ड Hinnant सही है ... अन्य संभावना आप यह सिर्फ एक पूरकता है, .: हर जगह संदर्भ का उपयोग करने के लिए, उदा

#include <iostream> 

struct DelayedSignal 
{ 
    ~DelayedSignal() 
    { std::cout << "~DelayedSignal CLOSE" << std::endl; } 

    template<class C, class... Args> 
    DelayedSignal (void(C::*func)(Args &...), C& obj) 
    { std::cout << "DelayedSignal INIT - 03 - pointer to method & pointer to class instance (Arg num: " << sizeof...(Args) << ")" << std::endl; } 

    template<class C, class... Args> 
    DelayedSignal (void(C::*func)(Args &...), C& obj, Args & ... args) 
    { 
     std::cout << "DelayedSignal INIT - 04 - pointer to method & pointer to class instance & arguments (Arg num: " << sizeof...(Args) << ")" << std::endl; 
    } 
}; 

template < class Tr, class... Args > 
struct Signal 
{ 
    void fire (Args &... args) { std::cout << "Signal::fire::" << sizeof...(Args) << std::endl; } 
}; 

struct Klass {}; 

int main() 
{ 
    std::string str1("Blop"); // Will be used as reference 
    Klass k;     // Will be used as reference 

    Signal<void, Klass&> signal_01; 
    Signal<void, std::string&> signal_02; 

    std::cout << "====== DelayedSignal :: needed for production purpose ===============" << std::endl; 

    // OK 
    DelayedSignal test01(&Signal<void, std::string&>::fire, signal_02); 
    // HERE IS THE PROBLEM 
    DelayedSignal test02(&Signal<void, std::string&>::fire, signal_02, str1); 

} 
+0

यह समाधान कम से कम आंशिक रूप से मेरी समस्या हल करता है। दोनों उत्तरों मान्य हैं, लेकिन जैसा कि मैं उनमें से केवल एक चुन सकता हूं, मैंने आंशिक समाधान वाले एक को चुना है। – Valkea

2

मैं बजना जो एक बिल्कुल शानदार त्रुटि संदेश देता है उपयोग कर रहा हूँ:

test.cpp:59:19: error: no matching constructor for initialization of 'DelayedSignal' 
    DelayedSignal test02(&Signal<void, std::string&>::fire, signal_02, str1); 
       ^ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
test.cpp:9:5: note: candidate constructor template not viable: requires 2 arguments, but 3 were provided 
    DelayedSignal (void(C::*func)(Args...), C& obj) 
    ^
test.cpp:13:5: note: candidate template ignored: deduced conflicting types for parameter 'Args' 
     (<std::__1::basic_string<char> &> vs. <std::__1::basic_string<char>>) 
    DelayedSignal (void(C::*func)(Args...), C& obj, Args... args) 
    ^

संकलक Args के लिए परस्पर विरोधी प्रकार deduces:

  1. std::string&
  2. std::string

मैं सबसे अच्छा वा विश्वास करो y ठीक करने के लिए यह है कि आपने अपने DelayedSignal_DebugHelper के साथ ऐसा कैसे किया है।

+0

हैलो, बहुत रोचक और ... अजीब। मेरा त्रुटि संदेश कम वर्णनात्मक है: 'main.cpp: 2: 74: त्रुटि: 'विलम्बित सिग्नल :: विलम्बित सिग्नल (शून्य (सिग्नल <शून्य (std :: basic_string और)> :: *) (std) को कॉल करने के लिए कोई मिलान करने वाला फ़ंक्शन नहीं :: basic_string और), सिग्नल और)> &, std :: string &) ' main.cpp: 57: 1: नोट: उम्मीदवार है: देरी से सिग्नल :: देरी से सिग्नल और (' लेकिन ऐसा लगता है कि आप विरोधाभासी प्रकारों के बारे में सही हैं। मुझे उसमें मुश्किल नहीं थी ... मुझे लगता है कि मुझे विलंबित सिग्नल को लागू करने के लिए अपना रास्ता बदलना होगा। आपके सहयोग के लिए धन्यवाद। – Valkea

1

आप एक जवाब के रूप में स्वीकार कर लिया है है। हालांकि मैं कुछ को अनदेखा कर सकता हूं, identity वर्ग टेम्पलेट जैसा कि आपके कोड को संकलित करने के लिए लगता है।
उदाहरण के लिए:

template<class T> struct identity { typedef T type; }; 

struct DelayedSignal 
{ 
    ... 
    template<class C, class... Args> 
    DelayedSignal (void(C::*func)(Args...), C& obj, typename identity<Args>::type... args) 
    { 
     ... 
    } 
}; 

यहाँ एक test on ideone

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