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
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.
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.
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 {}; }
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With