Można i tak i uważacie że jest to w tym przypadku najlepsze?
Z opisu problemu jaki przedstawiłeś, wg. mnie najlepsze byłoby połączenie podejścia łączonego z podejściem czysto szablonowym....
Otóż jako twórca biblioteki chcesz zapewnić jak najniższy próg wejścia użytkownikowi, podejście z dziedziczeniem jak i łączone (szablony + dziedziczenie) absolutnie Ci tego nie zapewnia. Użytkownik kontenera musi wiedzieć o różnych specjalizacjach zamiast operować na jednym interfejsie. Dla mnie słabo. Dlatego jakbym chciał stworzyć taką bibliotekę, interfejs stworzyłbym całkowicie szablonowy, ale żeby nie kopiować masywnej ilości kodu, w wewnętrznej implementacji użyłbym podejścia łączonego.
#include <iostream>
#include <memory>
/*
Wewnetrzna implementacja, nie widzialna dla uzytkownika
*/
template<class T>
struct Base {
virtual void common() {std::cout << "common\n";};
virtual void typeDependent(T val) {
//
std::cout << "Base call\n";
}
};
struct Derived : public Base<uint8_t> {
void typeDependent(uint8_t val) override {std::cout << "Derived call " << (int)val;}
};
/*
Interfejs biblioteki
*/
template<class T>
struct Container {
Container()
// c++14 std::make_unique
: _impl(new Base<T>()) {}
void common() {_impl->common();};
void typeDependent(T val) {
_impl->typeDependent(val);
}
//private
std::unique_ptr<Base<T>> _impl;
};
template<>
struct Container<uint8_t> {
Container()
// c++14 std::make_unique
: _impl(new Derived()) {}
void common() {_impl->common();};
void typeDependent(uint8_t val) {
_impl->typeDependent(val);
}
//private
std::unique_ptr<Derived> _impl;
};
int main() {
Container<uint8_t> der;
der.common();
der.typeDependent(2);
return 0;
}
Dzięki temu ułatwiasz pracę sobie bo nie musisz kopiować zbyt dużej ilości kodu między specjalizacjami, oraz ułatwiasz pracę użytkownikowi bo nie musi wiedzieć o poszczególnych specjalizacjach.