2013-06-03 21 views
12

Próbuję użyć dedukcji argumentu szablonu z dziedziczeniem i std::shared_ptr. Jak widać w przykładowym kodzie poniżej, przekazuję shared_ptr<Derived> do szablonowej funkcji nie należącej do członka, która powinna wykonać dedukcję argumentu szablonu. Jeśli ręcznie nazwiesz wszystko, wszystko działa, a jeśli pozwolę na to odejście od szablonu, to nie działa. Wydaje się, że wydaje się być tak, jakby kompilator nie mógł określić typu, jednak komunikat o błędzie pokazuje, że tak się stało. Nie jestem pewien, co się tutaj dzieje i byłbym wdzięczny za wszelkie uwagi. (Visual Studio 2010)Problem z odstąpieniem od argumentu std :: shared_ptr, dziedziczenia i szablonu

#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; 
} 

Komunikat o błędzie:

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

Oto co GCC 4.7.3 ma do powiedzenia na ten temat, FYI: 't.cpp: 9: 6: uwaga: szablon argumentu odliczenie/substytucja nie powiodło się: t.cpp: 16: 47: Uwaga: niedopasowane typy" baza "i 'pochodne' t.cpp: 16: 47: Uwaga: 'std :: shared_ptr ' nie pochodzi od 'std :: shared_ptr >'' –

Odpowiedz

10

Podczas gdy kompilator może wykonywać pochodzi to Base konwersje robiąc typu odliczenia std::shared_ptr<Derived> robi nie sam czerpać z std::shared_ptr<Base<int>>.

Istnieje konwersja zdefiniowana przez użytkownika między tymi dwoma, która pozwala shared_ptr zachowywać się jak regularne wskaźniki w odniesieniu do polimorfizmu, ale kompilator nie bierze pod uwagę konwersji zdefiniowanych przez użytkownika podczas wykonywania odliczenia typu.

bez uwzględnienia zdefiniowany przez użytkownika conversiosn, kompilator nie może wyprowadzić T która stałaby shared_ptr<Base<T>> albo identyczne shared_ptr<Derived> lub klasy bazowej shared_ptr<Derived> (po raz kolejny, shared_ptr<Base<int>> jest nie klasa bazowa shared_ptr<Derived>).

Dlatego odliczanie typu nie powiedzie się.

Aby obejść ten problem, można pozwolić parametr swojej funkcji jest prosty shared_ptr<T>i dodać SFINAE-ograniczenie, że upewnij się, że przeciążenie jest odbierane tylko wtedy, gdy typ argumentu jest pochodną (lub jest) instancją szablonu Base klasy:

#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) 
{ 
    // ... 
} 

Oto live example.

+0

Niestety, 'decltype' et al. nie są dostępne w MSVC10. Dlaczego nie używasz 'is_base_of'? – dyp

+1

@DyP: 'decltype' et al. * są * dostępne w MSVC10 –

+0

@DyP: Huh, wydaje się, że dostępny jest tylko 'decltype', a nie" al .: ": D Cóż, w takim razie będę musiał trochę zmienić, masz rację –

0

Działa jeśli piszesz to tak:

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

Jeśli naprawdę chcesz jawnie zablokować funkcję od miano coś nie pochodzi z bazy, można użyć type_traits/enable_if/etc.

Powiązane problemy