2016-08-26 9 views
9

Mam następujący MWe:Czy istnieje sposób, aby dopasować zagnieżdżony typ szablonu niejawnie w C++?

#include <iostream> 
#include <memory> 

class A { 
public: 
    int n = 42; 
    typedef std::shared_ptr<A> Ptr; 
}; 

template<typename T> 
void foo(typename T::Ptr arg) { 
    std::cout << arg->n << std::endl; 
} 

template<typename T> 
void bar(T arg) { 
    std::cout << arg.n << std::endl; 
} 

int main() { 
    A::Ptr a = A::Ptr(new A()); 
    foo<A>(a); // Can I avoid giving <A> here explicitly. 
    // foo(a); // does not compile 
    bar(*a); // after all this does work 
    return 0; 
} 

Dla mnie to wygląda tak, jak powinno być również możliwe, aby zadzwonić foo(a) zamiast foo<A>(a). Dlaczego nie jest to możliwe i czy mogę jakoś zmienić definicję foo, aby było to możliwe?

Zdaję sobie sprawę, że mogę po prostu pominąć ::Ptr w podpisie, ale nadal chcę mieć dostęp do typu A bez wskaźnika.

Odpowiedz

8

To nie jest możliwe ponieważ jest kontekstem nieodwzajemnionym.

Rodzaj a tylko std::shared_ptr<A>, co oznacza raziefoo(a) prace, następnie następujące powinny również praca:

std::shared_ptr<A> x(new A()); 
foo(x); 

Jeśli tak, to jaki powinien T wywnioskować do — i czemu? Możesz pokusić się o stwierdzenie, że "T" należy wydedukować jako A, ponieważ A ma typ zagnieżdżony Ptr, który jest taki sam jak std::shared_ptr<A> ". A co, jeśli istnieje inna klasa zdefiniowana jako:

struct B 
{ 
    typedef std::shared_ptr<A> Ptr; 
}; 

Co T wywnioskować do? A lub B? albo coś innego?

Oto kolejny temat, który omawia zakaz wywnioskować kontekstowe używając innego przykładu:

nadzieję, że pomoże.

+0

co jest „zakaz kontekst, na który nakłada się "? jak to działa? gdzie to ma zastosowanie? – Ven

+1

To wyjaśnia. Dzięki. –

+3

@Ven W skrócie, dotyczy to sytuacji, gdy kompilator nie ma rozsądnego sposobu wyprowadzenia parametru, który pozostaje zdrowy w przypadku przypadków narożnych i nieograniczonego zestawu typów i wartości. Aby uzyskać bardziej formalne traktowanie, zapoznaj się z rozdziałem 14 standardu C++. – Angew

4

odpowiedź Nawaz za wyjaśnił dlaczego kod nie działa, będę koncentrować się na to pytanie:

ale nadal chcą mieć dostęp do rodzaju A bez wskaźnika.

std::shared_ptr ma typ użytkownika element_type, można go używać jak typename T::element_type. A jeśli chcesz kod działa dobrze z surowego wskaźnik też można zapewnić klasy cecha szablonu:

template <typename T> 
struct trait_element_type { 
    using element_type = std::remove_pointer_t<T>; 
}; 

template <typename T> 
struct trait_element_type<std::shared_ptr<T>> { 
    using element_type = T; 
}; 

a następnie użyć go jako:

template<typename T> 
void foo(T arg) { 

    std::cout << arg->n << std::endl; 

    typename trait_element_type<T>::element_type x; // retrieve the element type 
    std::cout << x.n << std::endl; 
} 

LIVE

+0

W specjalizacji może to być po prostu 'using element_type = T;' zamiast 'using element_type = nazwa-pliku std :: shared_ptr :: element_type;'. – Nawaz

+0

@Nawaz Ohh, tak, oczywiście. Dzięki. – songyuanyao

+1

Po prostu użyj 'std :: pointer_traits'. –

Powiązane problemy