2017-04-10 3 views
1

Ich habe diese einfache Funktion mit einem Template-Template-Parameter. Es sollte einen STL-Container nehmen, das Smart-ptr zu einem normalen ptr konvertieren (es ++ 03 C ist Projekt, aber ich bin auch in der Antwort interessiert für C++ 11):Vorlage Template-Klasse, eine Funktion aufrufen, wenn es existiert

template <template <typename _T, typename = std::allocator<_T> > class Container> 
static Container<T*> GetRawPtrContainer(const Container<SmartPtr<T> >& input_container) 
{ 
    Container<T*> container; 
    for(typename Container<SmartPtr<T> >::const_iterator it = input_container.begin(); 
     it != input_container.end(); 
     it++) 
    { 
     container.push_back(it->ptr); 
    } 
    return container; 
} 

Dies ist eine statische Elementfunktion der Klasse SmartPtr<T>.

Sie sehen hier, das alles ist push_back alle Elemente von input_container zu einem anderen und zurück.

Sie haben vielleicht bemerkt, dass, wenn der Eingang std::vector ist, dann gibt es ein Performance-Problem mit O(1) Einfügungen, während dies für std::list und std::deque in Ordnung ist. Also, was Ich mag würde zu tun ist, dieser Aufruf vor der Schleife, wenn es möglich ist (entschieden zur Compile-Zeit):

container.reserve(input_container.size()); 

Wie kann ich das tun?

Antwort

1

Überprüfen Sie, ob Klasse hat eine Reservefunktion:

C++ 03:

template<typename T> struct HasReserve { 
    struct Fallback { void reserve(size_t); }; 
    struct Derived : T, Fallback { }; 

    template<typename C, C> struct Check; 

    template<typename C> static char(&f(Check<void (Fallback::*)(size_t), &C::reserve>*))[1]; 
    template<typename C> static char(&f(...))[2]; 

    static bool const value = sizeof(f<Derived>(0)) == 2; 
}; 

C++ 11:

template <typename T, typename = int> 
struct HasReserve : std::false_type { }; 

template <typename T> 
struct HasReserve <T, decltype(&T::reserve, 0)> : std::true_type { }; 

Funktion, Anrufe reservieren, wenn möglich:

Rufen Sie einfach die Reserve-Funktion vor Ihrer Schleife und es sollte funktionieren, wie Sie es wollen.

template <template <typename _T, typename = std::allocator<_T> > class Container> 
static Container<T*> GetRawPtrContainer(const Container<SmartPtr<T> >& input_container) 
{ 
    Container<T*> container; 
    Reserve(container, input_container.size()); // just add this to your function 
    for(typename Container<SmartPtr<T> >::const_iterator it = input_container.begin(); 
     it != input_container.end(); 
     it++) 
    { 
     container.push_back(it->ptr); 
    } 
    return container; 
} 

std :: enable_if für C++ 03

template<bool B, class T = void> 
struct enable_if {}; 

template<class T> 
struct enable_if<true, T> { typedef T type; }; 
+0

Es tut mir leid, können Sie ein Beispiel zeigen, wo das C++ 03 Beispiel für das Problem arbeiten würde, das ich gestellt habe? –

+0

Einfach so: https://pastebin.com/c4NARK3e – ACB

+0

Könnten Sie das zur Antwort hinzufügen? Die Firewall meines Unternehmens blockiert pastebin. –

1

können Sie Überlastung verwenden

// Common code in general template and specialization 
template <template <typename _T, typename = std::allocator<_T> > class Container> 
static Container<T*> GetRawPtrContainer(const Container<SmartPtr<T> >& input_container,Container<T*> &container) 
{ 
    for(typename Container<SmartPtr<T> >::const_iterator it = input_container.begin(); 
     it != input_container.end(); 
     it++) 
    { 
     container.push_back(it->ptr); 
    } 
    return container; 
} 

// General template 
template <template <typename _T, typename = std::allocator<_T> > class Container> 
static Container<T*> GetRawPtrContainer(const Container<SmartPtr<T> >& input_container) 
{ 
    Container<T*> container; 
    return GetRawPtrContainer(input_container,container); 
} 

//Vector specialization 
template <template <typename _T> 
static Container<T*> GetRawPtrContainer(const std::vector<SmartPtr<T> >& input_container) 
{ 
    std::vector<T*> container; 
    container.reserve(input_container.size()); 
    return GetRawPtrContainer(input_container,container); 
} 
+0

@ W.F. das ist wahr, ich werde bearbeiten :) – amchacon

0

Hier ist ein 11 C++ Implementierung, die Container ist Agnostiker und Reserven Puffer der Eingangsbehälter eine .reserve Elementfunktion im Falle hat.

template<typename Container, typename T> 
auto 
insert(Container& container, T &&v, int) -> 
decltype(container.push_back(std::forward<T>(v)), void()) { 
    container.push_back(std::forward<T>(v)); 
} 

template<typename Container, typename T> 
void 
insert(Container &container, T &&v, ...) { 
    container.insert(std::forward<T>(v)); 
} 

template<typename T, template<typename...> class Container> 
auto 
GetRawPtrContainer_helper(Container<T> const &container, int) -> 
decltype(container.reserve(42), Container<typename T::element_type*>()) { 

    Container<typename T::element_type*> out; 
    out.reserve(container.size()); 
    for(auto &&e : container) insert(out, e.get(), 0); 

    return out; 
} 

template<typename T, template<typename...> class Container> 
Container<typename T::element_type*> 
GetRawPtrContainer_helper(Container<T> const &container, ...) { 

    Container<typename T::element_type*> out; 
    for(auto &&e : container) insert(out, e.get(), 0); 

    return out; 
} 

template<typename T, template<typename...> class Container> 
Container<typename T::element_type*> 
GetRawPtrContainer(Container<T> const &container) { 

    return GetRawPtrContainer_helper(container, 0); 
} 

Live Demo

Verwandte Themen