2013-06-03 25 views
12

Şablon argüman kesintisini kalıtım ve std::shared_ptr ile kullanmaya çalışıyorum. Aşağıdaki örnek kodda gördüğünüz gibi, şablon argümanı indirimi yapması gereken şablonlu bir işleve shared_ptr<Derived> aktarıyorum. Eğer el ile yazdığım herşeyi çalışırsa ve şablon argüman indirimi yapmasına izin verip vermezse. gibi görünüyor, derleyici türünü bulamadı, ancak hata mesajı gösterdi. Burada neler olduğundan emin değilim ve herhangi bir girdi için minnettar olurum. (Visual Studio 2010)Std :: shared_ptr, devralma ve template argüman indirgemeyle ilgili sorun

#include <memory> 

template <typename T> 
class Base {}; 

class Derived : public Base<int> {}; 

template <typename T> 
void func(std::shared_ptr<Base<T> > ptr) {}; 

int main(int argc, char* argv[]) 
{ 
    std::shared_ptr<Base<int>> myfoo(std::shared_ptr<Derived>(new Derived)); // Compiles 
    func(myfoo); // Compiles 
    func<int>(std::shared_ptr<Derived>(new Derived)); // Compiles 
    func(std::shared_ptr<Derived>(new Derived)); // Doesn't compile. The error message suggests it did deduce the template argument. 

    return 0; 
} 

hata iletisi:

5> error C2664: 'func' : cannot convert parameter 1 from 'std::tr1::shared_ptr<_Ty>' to 'std::tr1::shared_ptr<_Ty>' 
5>   with 
5>   [ 
5>    _Ty=Derived 
5>   ] 
5>   and 
5>   [ 
5>    _Ty=Base<int> 
5>   ] 
5>   Binding to reference 
5>   followed by 
5>   Call to constructor 'std::tr1::shared_ptr<_Ty>::shared_ptr<Derived>(std::tr1::shared_ptr<Derived> &&,void **)' 
5>   with 
5>   [ 
5>    _Ty=Base<int> 
5>   ] 
5>   c:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\include\memory(1532) : see declaration of 'std::tr1::shared_ptr<_Ty>::shared_ptr' 
5>   with 
5>   [ 
5>    _Ty=Base<int> 
5>   ] 
5> 
+2

İşte GCC 4.7.3 Bilginize, bu konuda söylenecek vardır ne: 't.cpp: 9: 6: not: şablon argümanı kesinti/ikame başarısız oldu: t.cpp: 16: 47: not: uyumsuz türleri ' Temel 've' Türetilmiş ' t.cpp: 16: 47: not:' std :: shared_ptr ',' std :: shared_ptr > '' –

cevap

10

derleyici can tip kesinti yaparken türetilmiş-to-baz dönüşümleri gerçekleştirmek, std::shared_ptr<Derived> kendisi std::shared_ptr<Base<int>> türetmek değil yok iken.

shared_ptr, polimorfizm açısından düzenli işaretçiler gibi davranmasına izin veren ikisi arasında kullanıcı tanımlı bir dönüşüm var, ancak derleyici, tür kesintisi gerçekleştirilirken kullanıcı tanımlı dönüşümleri dikkate alamaz.

kullanıcı tanımlı conversiosn dikkate almadan, derleyici shared_ptr<Base<T>> ya özdeş shared_ptr<Derived> veya shared_ptr<Derived> bir temel sınıf kılacak bir T anlamak olamaz (bir kez daha, shared_ptr<Base<int>>olupshared_ptr<Derived> bir taban sınıfı).

Bu nedenle, tür kesinti başarısız olur.

Bu soruna için, fonksiyonun parametre basit shared_ptr<T>ve senin aşırı yük argüman türü türetilmiştir yalnızca aldı emin kılacak bir SFINAE-kısıtlaması ekleme olsun (veya verebilir İşte

#include <type_traits> 

namespace detail 
{ 
    template<typename T> 
    void deducer(Base<T>); 

    bool deducer(...); 
} 

template <typename T, typename std::enable_if< 
    std::is_same< 
     decltype(detail::deducer(std::declval<T>())), 
     void 
     >::value>::type* = nullptr> 
void func(std::shared_ptr<T> ptr) 
{ 
    // ... 
} 

bir live example geçerli: Base sınıf şablonunun bir örneği) olduğunu.

template <typename T> 
void func(std::shared_ptr<T> ptr) {}; 

gerçekten açıkça Base türetilmiş değil şeyle denilmekten fonksiyonunu bloke etmek isterseniz,/enable_if/vb type_traits kullanabilirsiniz: Eğer bu şekilde yazarsanız

+0

'dan türetilmiştir, ne yazık ki, decltype' ve ark. MSVC10'da mevcut değildir. Neden is_base_of' kullanmıyorsunuz? – dyp

+1

@DyP: 'decltype' et al. * vardır * MSVC10 –

+0

@DyP'de kullanılabilir: Huh, sadece "decltype" var, "al .:" değil gibi görünüyor: D Eh, bu durumda bir şeyleri biraz değiştirmem gerekecek, sen haklısın –

0

Çalışıyor.