2016-08-26 5 views
9

Ich habe folgendes MWE:Gibt es eine Möglichkeit, einen verschachtelten Vorlagentyp implizit in C++ zu finden?

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

Für mich sieht es aus wie es auch möglich sein sollte foo(a) statt foo<A>(a) zu nennen. Warum ist das nicht möglich und kann ich die Definition von foo irgendwie ändern, um dies zu ermöglichen?

Ich realisiere, dass ich einfach die ::Ptr in der Signatur überspringen konnte, aber ich möchte immer noch Zugriff auf die A Art ohne den Zeiger haben.

Antwort

8

Das ist nicht möglich weil das nicht nachvollziehbare Kontext ist.

Die Art der a ist nur std::shared_ptr<A>, was bedeutet, wennfoo(a) Werke, dann sollte folgende auch Arbeit:

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

Wenn ja, dann was soll T-— abgeleitet werden und Warum? Sie könnten versucht sein zu sagen: "T sollte zu A abgeleitet werden, da A einen verschachtelten Typ Ptr hat, der gleich std::shared_ptr<A> ist". Nun, was ist, wenn es eine andere Klasse wie folgt definiert:

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

Was soll T zu ableiten? A oder B? oder etwas anderes?

Hier ist ein weiteres Thema, das nicht ableitbar Kontext mit einem anderen Beispiel diskutiert:

Hoffnung, das hilft.

+0

was ein „nicht ist -dezierbarer Kontext "? wie funktioniert es? Wo gilt es? – Ven

+1

Das macht es klar. Vielen Dank. –

+3

@Ven Kurz gesagt, gilt es immer dann, wenn der Compiler keinen vernünftigen Weg hat, den Parameter abzuleiten, der bei Vorhandensein von Eckfällen und einer unbegrenzten Menge von Typen und Werten normal bleibt. Für eine formalere Behandlung verweisen wir auf Kapitel 14 des C++ - Standards. – Angew

4

Nawaz Antwort hat erklärt, warum der Code nicht funktioniert, werde ich auf diese Frage konzentrieren:

aber ich will noch Zugang zum A Typ ohne den Zeiger haben.

std::shared_ptr hat ein Mitglied Typ element_type, könnten Sie es wie typename T::element_type verwenden. Und wenn Sie den Code funktioniert gut mit Rohzeiger zu wollen, könnten Sie eine Eigenschaft Klassenvorlage bieten:

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

Und dann verwenden Sie es als:

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

In der Spezialisierung könnte es nur 'using element_type = T;' anstelle von 'using element_type = typenname std :: shared_ptr :: element_type;' sein. – Nawaz

+0

@Nawaz Ohh, ja, natürlich. Vielen Dank. – songyuanyao

+1

Verwenden Sie einfach 'std :: pointer_traits'. –

Verwandte Themen