Kiedy znajdziesz się w potrzebie częściowo specjalizujący szablon funkcji (uwaga, to nie znaczy, że w tym przypadku jesteś w potrzebie, jak DyP's answer pokazach), można albo ośrodek przeciążenia (patrz ostatnia aktualizacja na końcu tej odpowiedzi) lub, jeżeli nie jest to możliwe, należy owinąć ten szablon funkcji do szablonu klasy i mieć statyczny, funkcję składową non-template zastąpić oryginalny szablon funkcji (i jego specjalizacji):
namespace detail
{
template<class T, int N>
struct helper
{
static constexpr T pow(const T x){
return helper<T, N-1>::pow(x) * x;
}
};
template<class T>
struct helper<T, 1> // Unnecessary specialization! (see the edit)
{
static constexpr T pow(const T x){
return x;
}
};
template<class T>
struct helper<T, 0>
{
static constexpr T pow(const T x){
return 1;
}
};
}
Następnie można podać szablon funkcji pomocnika, który deleguje do specjalizacji szablonu klasy pomocnika:
template<int N, class T>
T constexpr pow(T const x)
{
return detail::helper<T, N>::pow(x);
}
Oto live example.
EDIT:
Zauważ, że specjalizacja dla N == 1
to faktycznie nie jest to konieczne. Zachowałem to w oryginalnym tekście, ponieważ celem tej odpowiedzi było przede wszystkim pokazanie, jak obejść niemożliwość częściowego wyspecjalizowania szablonów funkcji ogólnie - więc przetłumaczyłem oryginalny program kawałek po kawałku.
Jak zauważył DYP in the comments jednak, to byłoby na tyle:
namespace detail
{
template<class T, int N>
struct helper
{
static constexpr T pow(const T x){
return helper<T, N-1>::pow(x) * x;
}
};
template<class T>
struct helper<T, 0>
{
static constexpr T pow(const T x){
return 1;
}
};
}
UPDATE:
Jako kolejny uwaga, proszę pamiętać, że nawet jeśli może funkcję specjalizują szablony (np. z wyraźnymi - nie częściowymi - specjalizacjami), generalnie nie jest to dobry pomysł, ponieważ specjalizacja szablonu funkcji zwykle nie zachowuje się tak, jak można by oczekiwać.
Większość z tych sytuacji, które mogą wydawać się prosić o specjalizacji szablonu funkcja może zostać osiągnięte poprzez przeciążenia, napędzany przez dobrze znanych technik, takich jak tag wysyłki.Przykładem jest proponowane przez Potatoswatter in the comments, wskazując, że std::integral_constant
mogłyby zostać wykorzystane w tej sytuacji:
template<class T>
inline constexpr T pow(const T x, std::integral_constant<T, 0>){
return 1;
}
template<class T, int N>
inline constexpr T pow(const T x, std::integral_constant<T, N>){
return pow(x, std::integral_constant<T, N-1>()) * x;
}
template<int N, class T>
inline constexpr T pow(const T x)
{
return pow(x, std::integral_constant<T, N>());
}
Jednak wszystkie te wytyczne na temat „jak rozwiązywać problemy, które wydają się wymagać szablonu funkcja częściową specjalizację” powinno być brane pod rozważyć, kiedy są naprawdę potrzebne. W tym konkretnym przypadku, jak wykazał DyP w swojej odpowiedzi, nie są.
czy jesteś pewien, że jest to szablon meta-programu? –
@ BЈовић Nie, to nie, ale dlaczego potrzebujesz metaprogramowania szablonów? Możesz użyć funkcji 'constexpr' (i ich wyników) również w metaprogramowaniu. – dyp
@ BЈовић: Poważnie, kogo to obchodzi? "Czy na pewno użyłeś niebieskiego młotka do tego paznokcia?" –