Są tu dwa różne czynniki.
Po pierwsze, możliwe jest zdefiniowanie szablonów, które są sparametryzowane przez rzeczy inne niż tylko typy. Na przykład, oto prosty typ array:
template <typename T, size_t N> struct Array {
T arr[N];
};
Możemy to wykorzystać jak
Array<int, 137> myArray;
Wiemy, że vector<int>
i vector<double>
są różne typy. Ale teraz musimy również zwrócić uwagę, że Array<int,137>
i Array<int,136>
to różne typy.
Po drugie, podczas korzystania z szablonów, kompilator musi być w stanie znaleźć wartość dla wszystkich argumentów szablonu. Gdy używasz klas szablonów, zazwyczaj podajesz wszystkie argumenty szablonu. Na przykład nie mów: vector x
, ale powiedz coś w stylu: vector<double> x
. Podczas korzystania z funkcji szablonu, przez większość czasu kompilator może obliczyć argumenty. Na przykład, aby użyć std::sort
, wystarczy powiedzieć coś
std::sort(v.begin(), v.end());
Jednakże, można również napisać
std::sort<vector<int>::iterator>(v.begin(), v.end());
być bardziej wyraźne. Ale czasami masz funkcję szablonu, dla której nie wszystkie argumenty mogą być odgadnięte. W przykładzie mamy to:
template <unsigned parseFlags>
GenericDocument& Parse(const Ch* str) {
RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
GenericStringStream<Encoding> s(str);
return ParseStream<parseFlags>(s);
}
Zauważ, że parametr parseFlags
szablon nie można wywnioskować jedynie z argumentów funkcji. W związku z tym, aby wywołać tę funkcję, musisz podać parametr szablonu, ponieważ w przeciwnym razie kompilator nie może go znaleźć. To dlaczego chcesz napisać coś podobnego
Parse<0>(myString);
Tu 0 jest argumentem szablonu (rozwiązany w czasie kompilacji) i myString
jest rzeczywisty argument (rozwiązany w czasie wykonywania).
Możesz faktycznie mieć metody, które łączą trochę wnioskowania typu i trochę jawnych parametrów. Na przykład w Boost jest funkcja lexical_cast
, która może wykonywać konwersje do i od typów łańcuchów. Funkcja Podpis przekonwertować z typu non-ciąg do typu string jest
template <typename Target, typename Source>
Target lexical_cast(const Source& arg);
Tutaj, jeśli zadzwonisz lexical_cast
, kompilator może dowiedzieć się, co Source
jest, ale nie można wywnioskować Target
bez pewnych wskazówek. Aby korzystać lexical_cast
zatem chcesz napisać coś podobnego
std::string myString = boost::lexical_cast<std::string>(toConvertToString);
Bardziej ogólnie, kompilator mówi, że trzeba podać jakąś liczbę argumentów szablonu (opcjonalnie 0) i będzie starał się wyprowadzić resztę. Jeśli to możliwe, świetnie! Jeśli nie, jest to błąd podczas kompilacji. Korzystanie z tego, jeśli chcesz, możesz napisać funkcję jak
template <int IntArgument, typename TypeArgment>
void DoSomething(const TypeArgument& t) {
/* ... */
}
Aby wywołać tę funkcję, trzeba by powołać go tak:
DoSomething<intArg>(otherArg);
Tutaj działa to bo ciebie musi jawnie powiedzieć kompilatorowi, co to jest IntArgument
, ale wtedy kompilator może wydedukować TypeArgument
z typu argumentu na DoSomething
.
Mam nadzieję, że to pomoże!
możliwy duplikat [Przyczyna użycia parametru szablonu typu non zamiast zwykłego parametru?] (Http://stackoverflow.com/questions/7395700/reason-for-using-non-type-template-parameter-instead- of-regular-parameter) –
Wyszukaj "parametr szablonu non-type". –