Home > front end >  variadic arguments which are all a specialization of a template type
variadic arguments which are all a specialization of a template type

Time:08-09

We can validate at compile time that an input to a function is a specialization of a template. I.E the following code validates that the input for f is some specialization of struct Holder.

template<typename T>
struct Holder<T> {...};

template<typename T>
void f(Holder<T> h) {...};

I want to validate that a set of variadic arguments are a specialization of a template. More precisely I want to differentiate between two consecutive sets of variadic arguments - a set which is a specialization of a template, and a set which isn't. Following is an example of how it might have looked like if the syntax allowed it to -

template<...Args1, ...Args2>
void f(Holder<Args1>.... args_which_are_specializations_of_Holder, Args2... args_which_are_not) {
  use_holders(args_which_are_specializations_of_Holder...);
  use_rest(args_which_are_not...);
  return;
}

Is this possible ?

Thanks,

CodePudding user response:

It's harder to mix variadic arguments like that. You can use std::tuple:

#include <tuple>
#include <cstdio>

template<typename T>
struct Holder {

};

template <class ...T1, class ...T2>
void f(const std::tuple<Holder<T1>...>& holders, const std::tuple<T2...>& non_holders) {
  std::printf("Holder count: %zu\n"
              "Non Holder count: %zu", sizeof...(T1), sizeof...(T1));
}

int main() {
  Holder<int> a;
  Holder<double> b;
  int c;
  double d;  

  f(std::tuple{a, b}, std::tuple{c, d});
}

CodePudding user response:

You can store the args in a tuple and calculate the index of the last Holder argument, then extract the Holder and normal arguments by index and forward them to the corresponding function.

#include <tuple>

template<class T>
constexpr bool is_holder = false;
template<class T>
constexpr bool is_holder<Holder<T>> = true;

template<class... Args>
void f(Args... args) {
  constexpr auto holder_index = (is_holder<Args>   ...   0);
  auto args_tuple = std::tuple(args...);

  [&args_tuple]<auto... Is>(std::index_sequence<Is...>) {
    use_holders(std::get<Is>(args_tuple)...);
  }(std::make_index_sequence<holder_index>{});

  [&args_tuple]<auto... Is>(std::index_sequence<Is...>) {
    use_rest(std::get<Is   holder_index>(args_tuple)...);
  }(std::make_index_sequence<sizeof...(Args) - holder_index>{});
}

Demo

  • Related