2010-05-27 24 views
7

Dizeleri tutan bir kabın (örneğin vector<string>, set<string>, list<string>) bulunduğu ve bir başlangıç ​​yineleyici ve bir son yineleyici verildiğinde, dizeleri işleyen yineleyici aralığı boyunca bir işlevim var.Stl_container_type <string> :: yineleyicisinin templated parametresini kabul et

Şu an işlev şöyle bildirilir:

template< typename ContainerIter> 
void ProcessStrings(ContainerIter begin, ContainerIter end); 

Şimdi operator*, önek operator++ uygulamasının örtük arabirimine uygun olan herhangi bir türü ve işlev çağrısında başka hangi çağrıları olursa olsun kabul eder.

Gerçekten yapmak istediğim, giriş miktarını (pseudocode uyarısı) açıkça kısıtlayan aşağıdaki gibi bir tanıma sahip olacaktır:

template< typename Container<string>::iterator> 
void ProcessStrings(Container<string>::iterator begin, Container<string>::iterator end); 

bu şekilde kullanabilirsiniz:

vector<string> str_vec; 
list<string> str_list; 
set<SomeOtherClass> so_set; 

ProcessStrings(str_vec.begin(), str_vec.end()); // OK 
ProcessStrings(str_list.begin(), str_list.end()); //OK 
ProcessStrings(so_set.begin(), so_set.end()); // Error 

Esasen, yapmaya çalıştığım şey, işlev belirtimini, kabul ettiği işlevin bir kullanıcısı için açık hale getirecek şekilde kısıtlamak ve kodun derlenememesi durumunda, yanlış parametre türlerini kullandıklarını belirten bir ileti almalarıdır. XXX gövdesinde XXX işlevinin bulunamayacağı işlev gövdesindeki bir şey.

+0

Bunu 'std :: string' veya herhangi bir 'std :: basic_string 'türüyle kısıtlamak ister misiniz? –

+0

Ah, birisi aslında _needs_ __concepts__! Ne yazık ki, geçen yaz, C++ standartlaştırma komitesinin ön plana çıkan bir üyesinin tavsiyesi üzerine, aşırıya kaçtılar çünkü C++ 0x'in gelecek olanı, 'x', onaltılı bir basamak haline geldiği noktaya ertelediler. – sbi

+0

Şablonunuzu neyin arayabileceğini kısıtlamak için niçin İHTİYACINIZ VAR? Şablonun bütün noktası, iyi yapılandırılmış algoritmaların yeniden kullanılmasını sağlar. – jmucchiello

cevap

4

Bir şablon şablon parametresi ile bu yakın alabilirsiniz:

template<template<class> class CONTAINER> 
void ProcessStrings(CONTAINER<string>&); 

Bu tamamen kapsayıcı işleyecek ve bu dizeleri içermiyorsa bir derleme hatası verir. Eğer yineleyici aralıkları ile çalışmak istiyorsanız

ProcessStrings(str_vec); // OK 
ProcessStrings(so_set); // Error 

, o zaman olabilir yöneticisi açıkça gerekecek böylece

template<template<class> class CONTAINER> 
void ProcessStrings(typename CONTAINER<string>::iterator, 
        typename CONTAINER<string>::iterator); 

Maalesef tür kesmesi, fonksiyon argümanları çalışmaz en iyisi şablon parametresini veriniz:

Bunu geliştirebilecek biri var mı?

+1

'Şablon CONTAINER' kullanarak, şablon parametresinin tam sayısını belirtmeniz gerektiği için işe yaramazsa şaşırdım. Sadece konuştuğumuz konteynere bağlı olarak birkaç tane var. STL uygulaması, uygun varsayılan değerlere sahip oldukları sürece bazı ek parametreler ekleyebilirler .... –

+0

@Matthieu: Şablon argüman indiriminin, bir eşleşme bulmak için varsayılan argümanları doldurabileceğinden eminim. Kesinlikle, bu kod gcc ile test ettiğimde çalıştı. –

2

boost::enable_if şablon sihirbazını kullanarak bu tür kontrolleri uygulayabilirsiniz. Yineleyicinin değer türü, yazım dizgisi olmadığı sürece aşağıdaki yöntem derlenmeyecektir. boost::iterator_value<It>::type dize türünde ise

template<class It> 
boost::enable_if_c< 
     boost::is_same< typename boost::iterator_value<It>::type, string >::value 
>::type 
ProcessStrings(It itBegin, It itEnd) 
{ } 

, boost::enable_if<...>::type, iade parametresini geçersiz için değerlendirecektir. Aksi taktirde, SFINAE (ikame hatası başarısızlık) ilkesi nedeniyle, yöntem hata olmadan derlenmeyecektir.

+1

İşlev gövdesi içinde 'enable_if' veya' static_assert' çalışmalıdır. 'Void' dönüş türünü kaldırın ('enable_if''in işini burada belirtmek üzere). –

+0

@Matthieu Teşekkürler, haklısınız. Boş dönüş değeri bir yazım hatasıydı. – Sebastian

0

#include <string> 
#include <vector> 
#include <list> 

template<template<typename T,typename A> class C> 
void ProcessStrings(typename C<std::string, std::allocator<std::string> >::iterator begin, 
        typename C<std::string, std::allocator<std::string> >::iterator end) 
{ 
} 


int main() 
{ 
    std::vector<std::string> strVec; 
    std::list<std::string>  strList; 
    std::list<int>    intList; 

    ProcessStrings<std::vector>(strVec.begin(), strVec.end()); 
    ProcessStrings<std::list>(strList.begin(), strList.end()); 
    ProcessStrings<std::list>(intList.begin(), intList.end()); // This will fail 
} 
+0

Bu cevabın Mike'ınkinden nasıl farklılaştığını genişletebilir misiniz? Ben allocator parametresini belirtir görüyorum, ama gerçekten çok önemli bir fark var mı? –

+0

Gönderdiğimde Mikes'i görmedim. Ama daha yeni denedim ve kap şablonundaki tüm tip parametrelerini açıkça belirtmeden çalışmasını sağlayamıyorum. Bu benim derleyici ya da başka bir şey olup olmadığını çok fazla sorunu çözmek için denemedim bilmiyorum. –

1

basit ama etkili bir yol deneyin.Sonra

template <class T> 
struct is_basic_string: boost::mpl::false_ {}; 

template <class CharT, class Traits, class Alloc> 
struct is_basic_string< std::basic_string<CharT, Traits, Alloc> >: 
    boost::mpl::true_ {}; 

Ve, değer türü

void ProcessStrings(Iterator begin, Iterator end) 
{ 
    BOOST_MPL_ASSERT_MSG(
    is_basic_string< typename boost::value_type<Iterator>::type >, 
    ONLY_ACCEPT_ITERATOR_TO_BASIC_STRING, 
    (Iterator) 
); 

    // do your work 
} 

kontrol referansı here kontrol etmek için kullanabilirsiniz, bu makro derleme anda mümkün olduğu kadar anlamlı mesajlar sunmayı amaçlar.

Ayrıca bu, Sebastian çözümünden biraz daha geneldir ... ancak std::wstring uluslararasılaştırma için oldukça kullanışlıdır ve bunu yapmak istemezsiniz.

Şimdi çok iyi bir soru ... neden bunu yapmak isterdiniz?

Genel programlamanın amacı, dahili olarak kullandıkları işlemlere uyan herhangi bir türle çalışabilen işlevler üretmektir. Bunu neden kısıtlamak istiyorsun?

+0

Sorunun ilginç bir uzantısı olan 'basic_string' kullanma hakkında ek bilgi için teşekkürler. Jmucchiello'nun orijinal sorudaki bir yoruma, son paragrafta sorunuza bir tür açıklama sunmayı umduğum yanıtını verdim. –

İlgili konular