2010-03-29 25 views
7

Aşağıdaki örneği göz önünde bulundurun:Belirli bir tür özelliği olan tüm tipler için nasıl bir işlev şablonu yazabilirim?

struct Scanner 
{ 
    template <typename T> 
    T get(); 
}; 

template <> 
string Scanner::get() 
{ 
    return string("string"); 
} 

template <> 
int Scanner::get() 
{ 
    return 10; 
} 

int main() 
{ 
    Scanner scanner; 
    string s = scanner.get<string>(); 
    int i = scanner.get<int>(); 
} 

Scanner sınıfı, bazı kaynaklardan tokenleri ayıklamak için kullanılır. Yukarıdaki kod iyi çalışıyor, ancak get veya unsigned int gibi get diğer tümleşik türleri denediğimde başarısız oluyor. Bu türleri okuyabilecek kod, int değerini okuyacak kodla tamamen aynıdır. Okumak istediğim diğer tüm integral türleri için kodu çoğaltabilirim, ancak tüm integral tipler için bir fonksiyon şablonunu tanımlamayı tercih ederim.

Aşağıdakileri denedim:

struct Scanner 
{ 
    template <typename T> 
    typename enable_if<boost::is_integral<T>, T>::type get(); 
}; 

Bir çekicilik gibi çalışır, ancak Scanner::get<string>() işlevini yeniden nasıl çalıştıracağından emin değilim. Bu yüzden, scanner.get<string>() ve scanner.get<any integral type>() yapabilmem ve tüm ayrılmaz türlerini okumak için tek bir tanıma sahip olabilmem için kodu nasıl yazabilirim?

Güncelleme: bonus soru: Birden fazla sınıf aralığını bazı özelliklere göre kabul etmek istiyorsam ne yapmalıyım? Örneğin: (i) tümleşik türleri (ii) sırasıyla kayan nokta türleri (iii) dizeleri kabul eden üç get işlevine sahip olmak istiyorsanız, bu soruna nasıl yaklaşmalıyım.

cevap

10
struct Scanner 
{ 
    template <typename T> 
    typename boost::enable_if<boost::is_integral<T>, T>::type get() 
    { 
     return 10; 
    } 
    template <typename T> 
    typename boost::disable_if<boost::is_integral<T>, std::string>::type get() 
    { 
     return "string"; 
    } 
}; 

Güncelleme

struct Scanner 
{ 
    template <typename T> 
    typename boost::enable_if<boost::is_integral<T>, T>::type get() 
    { 
     return 10; 
    } 

    template <typename T> 
    typename boost::enable_if<boost::is_floating_point<T>, T>::type get() 
    { 
     return 11.5; 
    } 

    template <typename T> 
    std::string get(
      typename boost::disable_if<boost::is_floating_point<T>, T>::type* = 0, 
      typename boost::disable_if<boost::is_integral<T>, T>::type* = 0) 

    { 
     return std::string("string"); 
    } 
}; 
+2

“disable_if” dosyasındaki argümanları birleştirmek için muhtemelen “boost :: mpl :: and_” ve “boost :: mpl :: or_” komutlarını kullanabileceğinizi belirtmek isterim. +1 yine de :) –

+0

Ayrıca Boost kütüphanesinden 'ice_and' ve' ice_or' kullanabilirsiniz. –

3

Başka bir şablona ertele. Burada ne istediğinizi için genel desen var: "Bazı özelliklere göre sınıflara birden fazla aralığını kabul etmek istersem ne"

template <typename T, bool HasTrait = false> 
struct scanner_impl; 

template <typename T> 
struct scanner_impl 
{ 
    // Implement as though the trait is false 
}; 

template <typename T> 
struct scanner_impl<true> 
{ 
    // Implement as though the trait is true 
}; 

// This is the one the user uses 
template <typename T> 
struct scanner : scanner_impl<T, typename has_my_trait<T>::value> 
{ 
}; 
+1

Bu şekilde dolaylı yol eklemek iyi bir fikirdir. Belki bir "bool", ancak bir "enum" kullanmazsanız, daha da esnek hale gelebilir. – xtofl

+0

@xtofl: Yep. Bu da bonus sorusu için cevap verirdi. –

İlgili konular