2013-03-22 22 views
5

Napisałem asynchroniczną klasę zadań, która działa od wieków. Używa ona std::vector jako podstawowej kolekcji do przechowywania zadań, a następnie przetwarza je później, jak można się spodziewać. Kiedy dodaję pracę, robi to push_back na tym vector.Pisanie szablonu, który może używać std :: vector lub std :: set

Niedawno zdecydowałem, że chcę wprowadzić szablonowy typ kolekcji, którego używa i sposób, w jaki ją napisałem, powinno być bardzo proste. To teraz zadeklarowane tak:

template<typename J, typename CollectionT = std::vector<J>> 
class async_jobqueue 
{ 
public: 

Jest tylko jeden szkopuł, do pojemników typu vectorish chcę naciskać rzeczy na końcu kolekcji i nazwać push_back dla settish pojemnikach typu będę chciał zadzwonić insert. Jak mogę dokonać kompilacji decyzji o tym, do którego połączenia? A może jest przydatny adapter, którego mogę użyć?

+1

Sprawdź to: http://stackoverflow.com/questions/257288/is-it-possible-to-write-a-cplate-to-check-for-a-functions-existence. To dało mi spokój, kiedy to przeczytałem. – SirPentor

+0

@SirPentor To fajne, chociaż wygląda na to, że dałoby mi to sposób na ustalenie tego w czasie wykonywania. – Benj

+0

Użyj 'SFIANE' (http://en.wikipedia.org/wiki/SFINAE) lub specjalizuj lub szablon. – phoeagon

Odpowiedz

3

Przeciążenie i wywołanie go pod numerem end()? Jest dostępny w obu i powinien zrobić, co chcesz! Działa również na std::list!

Tu naprawdę nie ma potrzeby wysyłania.

+0

Oh my, nie mogę uwierzyć, że nie zauważyłem, że wstawka może przyjąć iterator ... – Benj

5

Wolałbym używać przeciążonej funkcji pomocnika. Poniższa jeden opiera się na fakcie, że nie standardowy pojemnik naraża zarówno pojedynczym argumentem insert() funkcji i push_back() funkcję:

#include <utility> 

template<typename C, typename T> 
auto insert_in_container(C& c, T&& t) -> 
    decltype(c.push_back(std::forward<T>(t)), void()) 
{ 
    c.push_back(std::forward<T>(t)); 
} 

template<typename C, typename T> 
auto insert_in_container(C& c, T&& t) -> 
    decltype(c.insert(std::forward<T>(t)), void()) 
{ 
    c.insert(std::forward<T>(t)); 
} 

to jak byś ich użyć:

#include <set> 
#include <vector> 
#include <iostream> 

int main() 
{ 
    std::set<int> s; 
    std::vector<int> v; 

    insert_in_container(s, 5); 
    insert_in_container(v, 5); 

    std::cout << s.size() << " " << v.size(); 
} 

A oto live example.

+0

Hmm, bardzo fajnie, wygląda na to. – Benj

+0

Czy używasz 'is_same' do indukowania SFINAE? – 0x499602D2

+0

@David: Tak, to tylko podstęp. Oczywiście mogą istnieć inne sposoby: –

2

Od concepts-lite powinna być nadzieją pojawiały się w czasie dla C++ 14, równie dobrze mogę ci pokazać, w jaki sposób to zrobić wtedy:

template<typename J, typename CollectionT = std::vector<J>> 
class async_jobqueue 
{ 
    public: 

    requires Associative_container<CollectionT>() 
    void adding_function(const J& item) { 
     // Uses insert 
    } 

    requires Sequence_container<CollectionT>() 
    void adding_function(const J& item) { 
     // Uses push_back 
    } 
}; 

Oczywiście, nie jest to jeszcze możliwe (a może nigdy być). Jednak odbiór do koncepcji-lite jest całkiem pozytywny.

+0

+1, to jest fajne. Dziękuję za wprowadzenie go na –

+0

Tak, bardzo ładnie i czysto. – Benj

Powiązane problemy