2011-04-19 6 views
17

निम्नलिखित हेडर फाइल पर विचार करें:सी ++ में एमपीएल वेक्टर के सभी सदस्यों के लिए टेम्पलेट को स्पष्ट रूप से कैसे प्रारंभ करें?

// Foo.h 
class Foo { 
    public: 
     template <typename T> 
     void read(T& value); 
}; 

मैं स्पष्ट रूप से दृष्टांत के लिए सभी प्रकार के लिए एक स्रोत फ़ाइल में Foo::read सदस्य समारोह टेम्पलेट चाहते शामिल एक boost::mpl::vector में:

// Foo.cc 
#include <boost/mpl/vector.hpp> 
#include <boost/mpl/begin_end.hpp> 
#include "Foo.h" 

template <typename T> 
void Foo::read(T& value) { /* do something */ } 

typedef boost::mpl::vector<int, long, float> types; 

// template Foo::read<int >(int&); 
// template Foo::read<long >(long&); 
// template Foo::read<float>(float&); 

// instantiate automatically ??? 

क्या यह संभव है? अग्रिम धन्यवाद, डैनियल। तो फिर

// intermezzo 
template <typename T> struct Bar { 
    Bar<T>() { 
     void (Foo::*funPtr)(T&) = &Foo::read<T>; 
    } 
}; 

static Bar<int > bar1; 
static Bar<long > bar2; 
static Bar<float> bar3; 

: कारण इन्स्टेन्शियशन यह एक struct के निर्माता है, जो चर का तो घोषित किया जाता है में Foo::read<T> के सूचक के बताए कि लगता है, -

संपादित

मैं कुछ समाधान नहीं मिला प्रक्रिया को निम्नानुसार स्वचालित किया जा सकता है:

// Foo.cc continued 
template <typename B, typename E> 
struct my_for_each { 
    my_for_each<B, E>() { 
     typedef typename B::type T;  // vector member 
     typedef void (Foo::*FunPtr)(T&); // pointer to Foo member function 
     FunPtr funPtr = &Foo::read<T>; // cause instantiation? 
    } 

    my_for_each<typename boost::mpl::next<B>::type, E> next; 
}; 

template<typename E> 
struct my_for_each<E, E> {}; 

static my_for_each< boost::mpl::begin<types>::type, 
        boost::mpl::end<types>::type > first; 

लेकिन मुझे नहीं पता कि थाई एस समाधान पोर्टेबल और मानक अनुरूप है? (इंटेल और जीएनयू कंपाइलर्स के साथ काम करता है।)

+3

nitpick: सवाल एक बालक स्पष्ट हो सकता है अगर आपके 'Foo' वर्ग वास्तव में' Foo.h' – Mat

+0

@nitpick में एक 'read' सदस्य सिर: संपादित, मेरी गलती है, धन्यवाद –

+1

पूर्वप्रक्रमक का उपयोग कर के लघु आधारित समाधान, मुझे नहीं लगता कि यह संभव है। –

उत्तर

0

मुझे यकीन नहीं है कि यह आपकी समस्या का समाधान है, लेकिन हो सकता है कि आप टेम्पलेट विशेषज्ञता के साथ कर सकें।

नई हैडर:

// Foo.h 

template < typename T > 
struct RealRead; 

class Foo { 
    public: 
     template <typename T> 
     void read(T& value); 
}; 

template <typename T> 
void Foo::read(T& value) 
{ 
    RealRead<T>::read(value); 
} 

नए स्रोत:

template < > 
struct RealRead<int> 
{ 
    static void read(int & v) 
    { 
    // do read 
    } 
}; 
template < > 
struct RealRead<float> 
{ 
    static void read(float & v) 
    { 
    // do read 
    } 
}; 

//etc 

// explicitly instantiate templates 
template struct RealRead<int>; 
template struct RealRead<float>; 
1

आप स्पष्ट रूप से template class Foo<T>;

बैच इन्स्टेन्शियशन के लिए के रूप में के साथ एक दिया टी टेम्पलेट पैरामीटर के लिए फू का दृष्टांत कर सकते हैं, मुझे नहीं पता लगता है कि यह संभव है। हो सकता है कि वेरिएडिक टेम्पलेट्स के साथ इंस्टेंटिएट क्लास बनाना संभव हो ताकि Instantiate<Foo, int, short, long, float, etc> जैसे कुछ उपयुक्त टेम्पलेट्स को तुरंत चालू कर सकें, लेकिन इसके अलावा, आपको मैन्युअल इंस्टेंटेशन का सहारा लेना होगा।

0

स्पष्ट तत्कालता में विशेष व्याकरण और अनुपालन के लिए विशेष अर्थ है, इसलिए मेटा प्रोग्रामिंग के साथ नहीं किया जा सकता है।

आपका समाधान एक तात्कालिकता का कारण बनता है, लेकिन एक स्पष्ट तत्काल नहीं है।

0

मुझे नहीं लगता कि यह आवश्यक है, और न ही यह संभव है।

आप किसी भी प्रकार के परिवर्तनीय पट्टी के लिए फ़ंक्शन: कॉल (बार) का उपयोग सीधे (कॉल) कर सकते हैं, जब तक कि आपके टेम्पलेट फ़ंक्शन कार्यान्वयन में टाइप अच्छी तरह परिभाषित न हो। कंपाइलर स्वचालित रूप से आपके तर्क को "टी" प्रकार में बदल देगा।

उदाहरण के लिए:

template <class T> 
Foo::read(T & var) 
{ 
    std::cin >> var; 
} 

टी अच्छी तरह से परिभाषित जब टी CIN द्वारा समर्थित एक स्ट्रीमिंग का प्रकार है।

उदाहरण "फू ::" हटा दिया गया है, तो उदाहरण स्वयं निहित होगा। मेरा मतलब है, "फू ::" के लिए, आपको इसे काम करने के लिए किसी वर्ग फू या नामस्थान फू को कहीं परिभाषित करना चाहिए था।

फिर भी उस टेम्पलेट हमेशा एक ज फ़ाइल, नहीं एक .cpp फ़ाइल के अंदर जाना चाहिए कृपया ध्यान दें (बस कीवर्ड के साथ वेब पर खोजें "C++ टेम्पलेट cpp फ़ाइल में लागू नहीं किया जा सकता"

+0

किसी .cpp फ़ाइल में टेम्पलेट को परिभाषित करना, फिर इसे कम करना (अधिक या कम) स्पष्ट रूप से एक सामान्य तकनीक है जब आप जानते हैं कि टेम्पलेट को किस तर्क के साथ शुरू किया जाना चाहिए। हेडर निर्भरता पक्ष पर प्राप्त करने के लिए बहुत कुछ है। – Quentin

0

आप उपयोग करना चाहते हैं आपकी कक्षा केवल एक मॉड्यूल में (यानी आप इसे निर्यात नहीं करेंगे) आप बूस्ट/एमपीएल/for_each का उपयोग कर सकते हैं। टेम्पलेट फ़ंक्शन इस तरह से परिभाषित किया गया है (mpl/for_each का उपयोग करके) निर्यात नहीं किया जाएगा (भले ही आप __declspec घोषित करें (निर्यात) से पहले वर्ग के नाम या समारोह हस्ताक्षर):

// Foo.cpp 
#include <boost/mpl/vector.hpp> 
#include <boost/mpl/for_each.hpp> 

template<class T> 
void read(T& value) 
{ 
... 
} 

using types = boost::mpl::vector<long, int>; 

//template instantiation 
struct call_read { 
    template <class T> 
    void operator()(T) 
    { 
    T t; //You should make sure that T can be created this way 
    ((Foo*)nullptr)->read<T>(t); //this line tells to compiler with templates it should instantiate 
    } 
}; 

void instantiate() 
{ 
    boost::mpl::for_each<types>(call_read()); 
} 

आप निर्यात/आयात आप संरचना और टेम्पलेट तरीकों की जरूरत है वहां बढ़ावा का उपयोग कर समाधान है/पूर्वप्रक्रमक

// Foo.h 
#ifdef <preprocessor definition specific to DLL> 
# define API __declspec(dllexport) 
#else 
# define API __declspec(dllimport) 
#endif 

class API Foo { 
public: 
    template<class T> void read(T& value); 
}; 

// Foo.cpp 
#include <boost/preprocessor/seq/for_each.hpp> 
#include <boost/preprocessor/seq/enum.hpp> 
#include <boost/mpl/vector.hpp> 

template<class T> 
void read(T& value) 
{ 
... 
} 

//using this macro you can define both boost::mpl structure AND instantiate explicitly your template function 
#define VARIANT_LIST (std::wstring)(long)(int) 
using types = boost::mpl::vector<BOOST_PP_SEQ_ENUM(VARIANT_LIST)>; 

//Here we should use our API macro 
#define EXPLICIT_INSTANTIATION(r, d, __type__) \ 
    template API void Foo::read<__type__>(__type__&); 
BOOST_PP_SEQ_FOR_EACH(EXPLICIT_INSTANTIATION, _, VARIANT_LIST) 

आप इस अतिरिक्त कार्यक्षमता पहला समाधान अधिक स्वच्छ मैं लंबे समय तक नहीं पहले

0

मैं एक ही आवश्यकता लिया है लगता है की जरूरत नहीं है, और एक सरल समारोह टेम्पलेट इन्स्टेन्शियशन अच्छे परिणाम मिले थे :

template <class... T> 
void forceInstantiation(typedef boost::mpl::vector<T...>*) { 

    using ex = int[]; 
    (void)ex{(void(&Foo::read<T>), 0)..., 0}; 

    // C++17 
    // (void)((void(&Foo::read<T>), ...)); 
} 

template void forceInstantiation(types*); 
संबंधित मुद्दे