Cześć wszystkim. Mam specyficzne pytanie odnośnie szablonów/klas :).
Czy jest możliwość określenia warunku, w którym metoda jest dołączana do klasy szablonowej, bądź staje się publiczna/prywatna? Ewentualnie, czy jest możliwe dodanie do dziedziczenia warunku, albo dynamiczna zmiana dostępu do metody?
Warunkiem takim byłaby sytuacja, w której tworzony jest szablon klasy, ale o określonym typie, np int/float (nakaz użycia wbudowanych typów) choćby poprzez sprawdzenie za pomocą typeid...
Istnieje co prawda sposób na ograniczenie tworzenia szablonów za pomocą biblioteki boost (std::is_integra, std::is_fundamentall), lecz czy istnieje sposób na zupełne ukrycie takiej metody/funkcji (zamiast ewentualnego ostrzeżenia od kompilatora w przypadku niewłaściwego użycia szablonu)?
Czy można zmienić widoczność (publiczna/prywatna) albo inaczej określić czy metoda ma być dostępna w zależności od parametru szablonu - nic nie przychodzi mi do głowy (std::enable_if
dla funkcji szablonowej, owszem). Czy można to zrobić dynamicznie? No tak, wsadź if
i rzucaj wyjątek, jeżeli typeid
pokaże, że typ jest nieprawidłowy (niedobre rozwiązanie, bo nie wiadomo co zwróci typeid
w ogólnym przypadku) Jeżeli chodzi o dziedziczenie to można tak:
#include <iostream>
template <typename T>
class Functionality {
};
template <>
class Functionality<int> {
public:
void function() {
std::cout << "Boo!\n";
}
};
template <typename T>
class StrangeClass : public Functionality<T> {
};
int main() {
StrangeClass<int> c1;
StrangeClass<float> c2;
c1.function();
// A to sie nie skompiluje:
//c2.function();
return 0;
}
Co do tych rzeczy z boost, to boost już nie jest do nich potrzebny. To jest w standardzie.
Opisz co Ty dokładnie kombinujesz, bo coś mi się wydaje, że konieczność robienia czegoś takiego może być efektem błędu w projekcie.
Stworzyłem klasę, która w założeniu jest listą (coś jak vector), w klasie tej mam metodę sortowania bąbelkowego, która działa prawidłowo na zmiennych fundamentalnych (lub innych z możliwym operatorem <). Chcę ograniczyć szablon tejże metody wyłącznie do zmiennych podstawowych.
Znalazłem następujące rozwiązanie (przykład prostej klasy):
#include <type_traits>
#include <iostream.h>
template <class T>
class Lol {
public:
template<class T>
typename std::enable_if<std::is_fundamental<T>::value, T>::type
foo1()
{
std::cout << "bla bla\n";
return 0;
}
};
main:
Lol <int> zonk; // okej
zonk.foo1<int>(); // okej
Lol <string> str; //okej
str.foo1<string>(); // blokada użycia metody :)
Error wynikający z blokady:
[BCC32 Error] File1.cpp(90): E2285 Could not find a match for 'Lol<string>::foo1<T>()'
Full parser context
File1.cpp(80): parsing: int wmain(int,wchar_t * *)
Taki sposób podoba mi się ze względu na to, że w razie niedozwolonego typu szablonu metody wyskoczy komunikat o błędzie, zamiast skoczyć w kompilatorze gdzieś głębiej (lokalizując problem). Natomiast nie podoba mi się użycie konkretyzacji szablonu przy każdorazowym wywołaniu. Lecz co jest pozytywne - w momencie wystukania na klawiaturze "zonk." kompilator podpowiada mi co znajduje się w klasie. Natomiast w metodzie kolegi powyżej tejże podpowiedzi nie ma w ogóle (co skutkuje nakazem pamiętania o metodzie). Ponad to... w moim przypadku definiuje klasę/metodę tylko RAZ.
Zastanawiałem się po prostu czy nie ma możliwości ukrycia szablonu metody, który nie spełnia kryteriów [to znaczy, widoczny tylko w odpowiednim szablonie (przez wpisanie "zonk." - a co za tym idzie... Jak myślę... usunięcie jawnego konkretyzowania szablonu przy wywołaniu ( czyli "zonk.foo1()" zamiast "zonk.foo1<int>()" ) ].
P.S. Jeśli chodzi o sens budowania takiej klasy to odpowiem następująco: Całą tą klasę tworze aby się lepiej zorientować w CPP :).
wg mnie powinno zadziałać:
template<> typename std::enable_if<std::is_fundamental<T>::value, T>::type foo1() ...
Żeby nie musieć pisać zonk.foo1<int>();
wystarczy zmienić ten kawałek:
template<class Tf = T>
typename std::enable_if<std::is_fundamental<Tf>::value, Tf>::type
To powinno spełniać wszystkie Twoje wymagania.
w klasie tej mam metodę sortowania bąbelkowego, która działa prawidłowo na zmiennych fundamentalnych (lub innych z możliwym operatorem <)
Ja tutaj w ogóle nie widzę tutaj potrzeby wykluczania specjalizacji. Szablony z C++ to nie generics z C#/Javy, gdzie musisz nakładać constraints. W C++ jest nim sam kod. Jeżeli wymagasz od typu tego, by miał zdefiniowany operator <
to skorzystaj z niego w kodzie i tyle. To taki szablonowy duck type'ing.
Obecnie tylko sztucznie ograniczasz możliwości klasy oraz zmieniasz treść błędu.