2016-11-03 51 views
6

zacząć, mam coś takiego:C++: Wniosek/wskaźnik zarejestrował zmienną jako parametr szablonu

class Test { 
    std::vector<int> a, b; 
    void caller(...) { callee(...); } 
    void callee(...) { /* Do stuff with 'a' */ } 
} 

Chciałem ma mieć funkcję, która robi dokładnie to samo callee ale dla wektora b. Aby to zrobić, istnieją dwie oczywiste rozwiązania:

  • Przełęcz wektorowe a lub b jako argument. Jednakże, callee jest funkcją rekursywną, która może służyć do setek wywołań, a przekazywanie wektorów jako argumentów byłoby niepotrzebne narzut.
  • Skopiuj funkcję callee i użyj wektora b, która byłaby najlepszą alternatywą, mimo że callee jest dość długą funkcją i miałbym dużo duplikatu kodu.

Z ciekawości poszedłem szukając części szablonów i zauważyłem, że może być stosowany do

lvalue reference type

pointer type

pointer to member type

Więc starałem się to zrobić:

class Test { 
    std::vector<int> a, b; 
    void caller(...) { callee<a>(...); } 
    template <std::vector<int> &x> void callee(...) { /* Do stuff with 'x' */ } 
} 

ale mam

error: use of ‘this’ in a constant expression

Czy można to osiągnąć za pomocą polecenia ence lub wskaźnik?

Nawiasem mówiąc, co chcę, może być postrzegane jako funkcja-scoped #define

+0

"i przekazywanie wektorów jako argumentów byłoby niepotrzebnym obciążeniem" Nie sądzę, że zauważysz nawet "obciążenie", gdy przekażesz wektor przez odniesienie lub wskaźnik. –

+0

Cóż, tak. Ale wolałbym raczej wybrać drugie rozwiązanie i nie mieć żadnych kosztów ogólnych. – gmardau

+0

Jeśli chcesz używać tego szablonu w sposób restrykcyjny, powinieneś zrobić 'template ' i gdziekolwiek używasz tego typu, zaakceptuj 'T &' - jeśli musisz zapobiec używaniu go, powiedz 'std: : vector 'następnie użyj' std :: enable_if' dla niezgodnego. – Olipro

Odpowiedz

3

tablic a nawet krotki, ale bez miłości do dobrych starych wskaźników do członków?

class Test { 
    std::vector<int> a, b; 

    void caller(/*...*/) { callee<&Test::a>(/*...*/); } 

    template <std::vector<int> Test::*vec> 
    void callee(/*...*/) { /* Do stuff with `(this->*vec)` */ } 
}; 
2

Wystarczy użyć elewacji:

class Test { 
    std::vector<int> a, b; 
    void caller_a(...) { callee(a); } 
    void caller_b(...) { callee(b); } 
    void callee(std::vector<int> &a_or_b, ...) { 
    } 
} 

callee() będzie odnosić się do jego parametr, który zostanie przekazany jako jeden lub inny członek klasy.

+0

To jest to, o czym wspomniałem w pierwszym rozwiązaniu punktorowym. – gmardau

4

Nie można użyć odwołania do elementu danych jako argumentu szablonu: szablony są kompilowane, a wartość this jest znana dopiero po uruchomieniu. Innymi słowy, potrzebujesz osobnego wystąpienia (oddzielnego kodu binarnego) dla każdego obiektu wykonawczego typu Test.

Co może zrobić, to wymienić a i b z tablicą i templatise callee przez indeks do tej tablicy:

class Test { 
    std::array<std::vector<int>, 2> ab; 
    void caller(...) { callee<0>(...); } 
    template <size_t idx> 
    void callee(...) { /* Do stuff with 'ab[idx]' */ } 
} 

W ten sposób można dostać tylko dwa dawałaby z callee (jeden dla 0 i jeden dla 1), z indeksowaniem zrobić (lub co najmniej wykonalne) w czasie kompilacji.

1

W tej samej logiki jak na @ Angew odpowiedź, można też użyć std :: krotki, i to dość ciekawy jak w krotce można również użyć innego rodzaju pojemników w funkcji odbierającego:

class Test { 
    std::tuple<std::vector<int>, std::list<int> > ab; 
    void caller(...) { callee<0>(...); } 
    template <size_t idx> 
    void callee(...) { 
    ... 
    auto aIt = std::get<idx>(ab).begin(); // gets either the vector or the list depending on template value 
    ... 
    } 
}