Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to write a function template which returns whether the number of arguments is divisible by N?

I've been learning about variadic templates, and with the help of this excellent blog post, I've managed to write a function template even_number_of_args which returns whether the number of arguments it receives is divisible by 2.

#include <iostream>  bool even_number_of_args() {     return true; }  template <typename T> bool even_number_of_args(T _) {     return false; }  template<typename T, typename U, typename... Vs> bool even_number_of_args(T _, U __, Vs... vs) {   return even_number_of_args(vs...); }  int main() {     std::cout << even_number_of_args()                   << std::endl; // true     std::cout << even_number_of_args(1)                  << std::endl; // false     std::cout << even_number_of_args(1, "two")           << std::endl; // true     std::cout << even_number_of_args(1, "two", 3.0)      << std::endl; // false     std::cout << even_number_of_args(1, "two", 3.0, '4') << std::endl; // true } 

I was wondering if it was possible to write a function template that takes, as a template argument, a number N and returns whether the number of arguments it receives is a multiple of N. For example, the function may look something like this:

number_of_args_divisible_by_N<1>(1, "two", 3.0, '4'); // true number_of_args_divisible_by_N<2>(1, "two", 3.0, '4'); // true number_of_args_divisible_by_N<3>(1, "two", 3.0, '4'); // false number_of_args_divisible_by_N<4>(1, "two", 3.0, '4'); // true 
like image 313
mwhittaker Avatar asked Sep 30 '16 00:09

mwhittaker


People also ask

Can there be more than one arguments to templates?

Can there be more than one argument to templates? Yes, like normal parameters, we can pass more than one data type as arguments to templates.

Can a template parameter be a function?

A template parameter is a special kind of parameter that can be used to pass a type as argument: just like regular function parameters can be used to pass values to a function, template parameters allow to pass also types to a function.


2 Answers

Yes, it's as simple as

template<int N, typename... Ts> constexpr bool number_of_args_divisible_by(Ts&&...) {     return sizeof...(Ts) % N == 0; } 

Alternatively, you can return a more metaprogramming-friendly type:

template<int N, typename... Ts> constexpr integral_constant<bool, sizeof...(Ts) % N == 0> number_of_args_divisible_by(Ts&&...) {     return {}; } 
like image 58
krzaq Avatar answered Sep 20 '22 19:09

krzaq


Although krzaq's solution is pretty good, I think that implementing the "magic" behind sizeof... can serve as an interesting learning exercise.

It uses a technique that is very common to template meta-programming - a non-template function covering the base case, and a template function that reduces the problem by one step:

// Base case int count_args() {     return 0; } // Reduction template<typename T, typename... Vs> int count_args(T _, Vs... vs) {     return 1 + count_args(vs...); } 

With this functionality in place, you can implement divisibility checker using the approach from krzaq's answer:

template<int N,typename... Vs> bool is_arg_divisible(Vs... vs) {     return count_args(vs...) % N == 0; } 

Demo.

like image 24
Sergey Kalinichenko Avatar answered Sep 21 '22 19:09

Sergey Kalinichenko