Wariacja parametrów szablonu funkcji

3

Hej Wszystkim,

Ostatnio czytając o meta programowaniu uruchomiłem fajny przykład wywołujący funkcję określoną ilość razy.

template <int N>
void Recurence()
{
    Recurence <N-1>();
}

template <>
void Recurence  <0>()
{
    //warunki końcowe
}

int main()
{
    Recurence <5>();
}

Jednak zastanawiam się, czy można iść dalej :) Czy można zrobić szablon wariadyczny, który przyjmie x argumentów i wywoła funkcję z ich wariacją. Czyli wywołanie np.

Funkcja (1,1);

Spowoduje rozpakowanie do funkcji do:

Funkcja(0,0);
Funkcja(1,0);
Funkcja(0,1);
Funkcja (1,1);

Wiadomo, że liczba wariacji będzie rosła potęgowo i w końcu włączy się ograniczenie kompilatora, ale warto spróbować dla samego doświadczenia. Próbuję się do tego zabrać, jednak ugrzązłem już na pierwszym etapie. Mam kilka pytań:

  • Czy można zrobić szablon wariadyczny z określonym typem? A dokładnie z wieloma parametrami typu int.
  • Jak wtedy ustalić warunki końcowe?
  • Do ilu rekurencji kompilatory najczęściej ograniczają szablon? Nie chodzi mi o dokładną liczbę, tylko czy jest to bardziej 100, czy 10^20 :)

Będę wdzięczny za każdą podpowiedź związaną z tematem.

2

Jeśli lubisz nowinki (C++17), coś takiego powinno dać radę:

#include <iostream>

template <unsigned int X, unsigned int Y>
void rec() {
  std::cout << "(" << X << "," << Y << ")\n";

  if constexpr (X > 0) {
    rec<X - 1, Y>();
  }

  if constexpr (Y > 0) {
    rec<X, Y - 1>();
  }

  if constexpr (X > 0 && Y > 0) {
    rec<X - 1, Y - 1>();
  }
}

int main() {
  rec<2, 2>();
}

Można by też dać radę bez if constexpr, wykorzystując SFINAE oraz enable_if - a przynajmniej tak mi się wydaje, choć sam nie dałem rady wykonać PoC :-P

Do ilu rekurencji kompilatory najczęściej ograniczają szablon?

AFAIK, przykładowo w GCC nie ma żadnego limitu - można pewien wymusić za pomocą -ftemplate-depth=...; nie jestem pewien co do reszty kompilatorów.

0

Czy można zrobić szablon wariadyczny, który przyjmie x argumentów i wywoła funkcję z ich wariacją

Ciekawe ćwiczenie umysłowe, ale Twoje przykłady nijak mają się do wariacji liczbowej. W kolejnych wywołaniach wykorzystujesz zero, którego nie ma w zadanym zbiorze w pierwszym wywołaniu. Ale żeby nie było że tylko się czepiam dodam coś w temacie.

Czy można zrobić szablon wariadyczny z określonym typem? A dokładnie z wieloma parametrami typu int.

Oczywiście. Do tego bardzo prosto można rozpakować parameter pack w takim przypadku:

template <size_t SIZE, typename... A>
constexpr std::array<int, SIZE> unpack(A&& ...args) {
    return {std::forward<A>(args)...};
}

const auto vals = unpack<3>(1,2,3);

Stała vals to tablica ze wszystkimi argumentami. Także w runtime mógłbyś wykonać na nich dowolną wariację jakiej potrzebujesz.

0
bilborrd napisał(a):
  • Czy można zrobić szablon wariadyczny z określonym typem? A dokładnie z wieloma parametrami typu int.

Po szablonach wciąż poruszam się jak dziecko we mgle, ale C++17 daje radę :)

template<typename T, typename... Ts>
inline constexpr bool all_same_v = std::conjunction_v<std::is_same<T, Ts>...>;

static_assert(all_same_v<int, int, int, int, int>); // OK
static_assert(all_same_v<int, int, float, int, int>); // FAIL
0
bilborrd napisał(a):
  • Czy można zrobić szablon wariadyczny z określonym typem? A dokładnie z wieloma parametrami typu int.

Wygląda na to, że trzeba skorzystać z std::integer_sequence.
Jak widać zmienna liczba argumentów szablonu, może mieć jeden określony typ.

Fajne zadanie i pewnie spróbuje je zrobić, ale że nie jest ono na "5 minut", to odłożę je na późnej.

Swoją drogą właściwe googlanie powinno dostarczyć gotowe rozwiązanie.

5

Ciekawy problem.
Starałem się napisać jak najwięcej na parametrach szablonów, ale przy find_index_to_inc musiałem już zaraz wychodzić z roboty, więc poszedłem na skróty

No i pewnie dało się to zrobić optymalnej w pewnych miejscach

Tak czy inaczej:
https://godbolt.org/z/E8up22

1 użytkowników online, w tym zalogowanych: 0, gości: 1