2010-11-03 22 views
12

पर विचार करें निम्नलिखित कोड का नेस्टेड वर्ग:सी ++: एक टेम्पलेट वर्ग

template < typename T > 
struct A 
{ 
    struct B { }; 
}; 

template < typename T > 
void f(typename A<T>::B) { } 

int main() 
{ 
    A<int>::B x; 
    f(x);   // fails for gcc-4.1.2 
    f<int>(x); // passes 
    return 0; 
} 

तो यहाँ जीसीसी-4.1.2 f के टेम्पलेट तर्क को स्पष्ट रूप से निर्दिष्ट करने की आवश्यकता है। क्या यह मानक मिलती है? क्या जीसीसी के नए संस्करणों में यह समस्या तय है? f पर कॉल करते समय मैं स्पष्ट रूप से int निर्दिष्ट करने से कैसे बच सकता हूं?

अद्यतन: यहां एक कामकाज है।

#include <boost/static_assert.hpp> 
#include <boost/type_traits/is_same.hpp> 

template < typename T > 
struct A 
{ 
    typedef T argument; 
    struct B { typedef A outer; }; 
}; 

template < typename T > 
void f(typename A<T>::B) { } 

template < typename Nested > 
void g(Nested) 
{ 
    typedef typename Nested::outer::argument TT; 
    BOOST_STATIC_ASSERT((boost::is_same< typename A<TT>::B, Nested >::value)); 
} 

struct NN 
{ 
    typedef NN outer; 
    typedef NN argument; 
}; 

int main() 
{ 
    A<int>::B x; 
    NN y; 
    g(x); // Passes 
    g(y); // Fails as it should, note that this will pass if we remove the type check 
    f(x); // Fails as before 

    return 0; 
} 

हालांकि, मैं अभी भी नहीं देख सकता कि क्यों f(x); कॉल अवैध है। क्या आप मानक में कुछ बिंदु देख सकते हैं जो कहता है कि ऐसी कॉल अमान्य होनी चाहिए? क्या आप एक उदाहरण ला सकते हैं जहां ऐसी कॉल संदिग्ध है?

उत्तर

10
typename A<T>::B 

यहाँ, T एक nondeduced संदर्भ, जिसका अर्थ है कि T समारोह तर्क से निष्कर्ष निकाला नहीं किया जा सकता है।

समस्या यह है कि सामान्य मामले में, संभावित प्रकारों की संभावना अनंत संख्या T है जो मिलान कर सकती है। उदाहरण के लिए, उदाहरण के लिए, struct B { }; के बजाय, आपके पास typedef int B; था।

+2

आपके उत्तर के लिए धन्यवाद। फ़ंक्शन तर्क से 'टी' क्यों नहीं लिया जा सकता है? क्या आप एक उदाहरण ला सकते हैं जहां 'टी' के लिए दो प्रकार हैं जो 'एफ' के एक विशेष कॉल के लिए मेल खाते हैं? क्या आपका मतलब है कि 'ए' की एक और विशेषज्ञता के लिए यह 'स्ट्रक्चर बी {}; 'के बजाय' typedef int b' हो सकता है? मैं नहीं देख सकता कि इस मामले में क्यों 'एफ' का आह्वान अस्पष्ट होना चाहिए। – Vahagn

0

मैं एफ कॉल करते समय int स्पष्ट रूप से निर्दिष्ट करने से कैसे बच सकता हूं?

आपको struct B से थोड़ी मदद की आवश्यकता होगी। वैकल्पिक रूप से कर सकता है सार mytypeof(x.getType()) दूर एक और समारोह जो च कॉल शुरू करने से

f(x, mytypeof(x.getType())); 

, आप, तो आप अपने मूल f(x) हो सकता है:

template < typename T > 
struct A 
{ 
    struct B 
    { 
     static T getType(); // no impl required 
    }; 
}; 

#define mytypeof(T) (true?0:T) 

template < typename T, typename U > 
void f(T t, U) { } // U will be T of A<T>::B 

यह निम्नलिखित के साथ कॉलिंग। जैसे

template < typename T, typename U > 
void b(T t, U) { } // U will be T of A<T>::B 

template < typename T > 
void f(T t) 
{ 
    b(t, mytypeof(t)); 
} 

तब आप f(x) पर कॉल कर सकते हैं।

+1

आपके उत्तर के लिए धन्यवाद। एक अतिरिक्त पैरामीटर जोड़ना मेरे लिए काम नहीं करेगा, क्योंकि वास्तव में मैंने 'f' के बजाय ऑपरेटरों को ओवरलैड किया है। – Vahagn

4

मैं एफ को कॉल करते समय स्पष्ट रूप से int निर्दिष्ट करने से कैसे बच सकता हूं?

बस B अपने घोंसले वर्ग प्रकार

template < typename T > 
struct A 
{ 
    struct B { typedef A outer; }; 
}; 

घोषित तो फिर तुम यह अनुमान लगा सकते हैं बनाते हैं।अगर यह अनुमति दी गई निम्नलिखित, बाहरी टेम्पलेट, भीतर के typedef और एक वापसी प्रकार

template<template<typename> class Outer, typename D, typename R = void > 
struct nesting { }; 

template<template<typename> class Outer, typename Arg, typename R> 
struct nesting< Outer, Outer<Arg>, R > { 
    typedef Arg arg1_type; 
    typedef R type; 
}; 

template < typename T > 
typename nesting<A, typename T::outer>::type 
f(T) { 
    /* nesting<A, typename T::outer>::arg1_type is A's T */ 
} 
0

में "अपडेट" सवाल पर बाद लेता है यहाँ एक स्थिति है जिसमें f करने के लिए कॉल अस्पष्ट होगा (, कि है):

// Definitions of generic "struct A", as well as "f()", are the same as above 

// But additionally, consider a specialized "struct A", defined as follows: 

template <> 
struct A<double> 
{ 
    typedef A<int>::B B; 
} 

// Now consider the call to "f", similarly to before: 

int main() 
{ 
    // Possibility 1 for argument to "f()" 
    // A<int>::B x; 

    // Possibility 2 for argument to "f()": Use the specialized version of "struct A" 
    A<double>::B x; 

    f(x); // which value to deduce for type T? Could be "int" or "double" 
} 

सूचना संभावित instantiated कार्यों f की अस्पष्ट जोड़ी: दोनों f<int>() और f<double>f() को एक सफल कॉल किए जाते हैं।

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