2010-06-09 35 views
15

Şablon bağımsız değişkeninin typedef'ini kullanan bir kod yazmayı deniyorum, ancak şablon argümanı bu typedef yoksa bir varsayılan tür sağlamak istiyorum.Sınıf üyesi typedef yoksa varsayılan türünü kullanmak için şablon uzmanlığı

struct DefaultType { DefaultType() { printf("Default "); } }; 
struct NonDefaultType { NonDefaultType() { printf("NonDefault "); } }; 

struct A {}; 
struct B { typedef NonDefaultType Type; }; 

template<typename T, typename Enable = void> struct Get_Type { 
    typedef DefaultType Type; 
}; 
template<typename T> struct Get_Type< T, typename T::Type > { 
    typedef typename T::Type Type; 
}; 

int main() 
{ 
    Get_Type<A>::Type test1; 
    Get_Type<B>::Type test2; 
} 

bu "Varsayılan varsayılan olmayan" yazdırmak için beklenir, ama bunun yerine "Standart" yazdırır: denedim bir basitleştirilmiş bir örnek şudur. Beklentim, ana() 'deki ikinci satırın, B :: Türünün mevcut olması nedeniyle Get_Type'ın özelleştirilmiş sürümüyle eşleşmesidir. Ancak, bu gerçekleşmez.

Burada neler olup bittiğini ve nasıl düzeltileceğini veya aynı amacı gerçekleştirmenin başka bir yolunu herkes anlatabilir mi?

Teşekkür ederiz.

Düzenleme:

Georg alternatif bir yöntem verdi ama hala bu neden çalışmıyor merak ediyorum. Gerçek enable_if <> bir typedef gibi yazması çünkü

template <class T, class Enable = void> 
class A { ... }; 

template <class T> 
class A<T, typename enable_if<is_integral<T> >::type> { ... }; 

template <class T> 
class A<T, typename enable_if<is_float<T> >::type> { ... }; 

Bu çalışır, ancak < yanlış> enable_if yapmaz: dokümanlar enable_if boost göre, farklı türleri için bir şablon uzmanlaşmak için bir yol öylesine gibidir.

Bunun sürümümden farklı olduğunu anlamıyorum, nerede enable_if kullanmak yerine doğrudan T :: Type kullanıyorum. T :: Type mevcut ise yukarıdaki örnekte enable_if < true> :: type ile aynı olmaz ve uzmanlığın seçilmesine neden olmaz mı? Ve eğer T :: Type yoksa, enable_if < false> :: type ile aynı olmaz ve yukarıdaki örnekte varsayılan versiyonun seçilmesine neden olmaz mı?

template<class T> struct has_type { 
    template<class U> static char (&test(typename U::Type const*))[1]; 
    template<class U> static char (&test(...))[2]; 
    static const bool value = (sizeof(test<T>(0)) == 1); 
}; 

template<class T, bool has = has_type<T>::value> struct Get_Type { 
    typedef DefaultType Type; 
}; 

template<class T> struct Get_Type<T, true> { 
    typedef typename T::Type Type; 
}; 
+0

Ah ait always .. hedefimiz nedir kullanabilir? –

+0

Hedef, Get_Type :: Type varsa T: Type, yoksa mevcut değilse DefaultType olacaktır. – Frank

cevap

8

Eklemenizi yanıtlamak için - uzmanlık argümanınız, üye typedef'i geçirir ve türünü void türünü elde etmesini bekler. Bu konuda bir sihir yok - sadece varsayılan bir argüman kullanıyor. Nasıl çalıştığını görelim. Get_Type<Foo>::type diyorsanız, derleyici, void olan Enable varsayılan değişkenini kullanır ve tür adı Get_Type<Foo, void>::type olur. Şimdi, derleyici herhangi bir kısmi uzmanlığın eşleşip eşleşmediğini kontrol eder. Kısmen uzmanlığınızın argüman listesi <T, typename T::Type>, <Foo, void> numaralı orijinal argüman listesinden çıkarılmıştır. Bu, Foo için T sonucunu çıkarır ve daha sonra, uzmanlığın ikinci argümanına Foo değiştirir ve kısmi uzmanlığınız için <Foo, NonDefaultType> sonucunu verir. Ancak, bu, orijinal argüman listesi <Foo, void> hiç uymuyor!

aşağıdaki gibi void tipini elde etmek için bir yol gerekir: beklediğiniz gibi

template<typename T> 
struct tovoid { typedef void type; }; 

template<typename T, typename Enable = void> struct Get_Type { 
    typedef DefaultType Type; 
}; 
template<typename T> 
struct Get_Type< T, typename tovoid<typename T::Type>::type > { 
    typedef typename T::Type Type; 
}; 

Şimdi bu işe yarar. MPL kullanarak, yerine tovoid

typename apply< always<void>, typename T::type >::type 
+0

Teşekkürler Johannes. Türün kendisinin eşleşmesi gerektiğini farketmedim, ama bu mükemmel bir anlam ifade ediyor. – Frank

7

Sen SFINAE kullanarak yapabilir.


BOOST_MPL_HAS_XXX_DEF(Type) 

template < typename T > 
struct get_type { typedef typename T::Type type; }; 

template < typename T > 
struct calculate_type : boost::mpl::if_ 
< 
    has_Type<T> 
, get_type<T> 
, boost::mpl::identity<default_type> 
>::type {} 

typedef calculate_type<A>::type whatever; 

bunun yerine metafunctions bunu dönüştürmek alıcısı "get_Type" gerek duymaz ve sadece bu durumda T geri dönebilirler "Türe" "tip" kullandıysanız

.

+0

Teşekkürler George, işe yarıyor. Uygulamamın neden çalışmadığıyla ilgili soruyu başka bir soruyla düzenledim, çünkü enable_if'in kendisi temel aldığı aynı prensip gibi görünüyor. enable_if bir yazım hatası içeriyor, ancak enable_if yapmıyor. Bunun neden T :: Type'un var olup olmadığını anlamıyorum. – Frank

+0

@Frank: Johannes bunu zaten başka bir cevapta güzelce yanıtladı. –

4

İlk adım: "Türü" kullanmayı bırakıp mpl standardını "tip" kullanmak

İlgili konular