J'ai appris sur les modèles variadiques, et avec l'aide de cet excellent article de blog , j'ai réussi à écrire un modèle de fonction even_number_of_args
qui retourne si le nombre d'arguments qu'il reçoit est divisible par 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
}
Je me demandais s'il était possible d'écrire un modèle de fonction qui prend, comme argument de modèle, un nombre N
et renvoie si le nombre d'arguments qu'il reçoit est un multiple de N
. Par exemple, la fonction peut ressembler à ceci:
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
Oui, c'est aussi simple que
template<int N, typename... Ts>
constexpr bool number_of_args_divisible_by(Ts&&...)
{
return sizeof...(Ts) % N == 0;
}
Alternativement, vous pouvez renvoyer un type plus adapté aux métaprogrammations:
template<int N, typename... Ts>
constexpr integral_constant<bool, sizeof...(Ts) % N == 0>
number_of_args_divisible_by(Ts&&...)
{
return {};
}
Bien que la solution de krzaq soit plutôt bonne, je pense que l'implémentation de la "magie" derrière sizeof...
peut être un exercice d'apprentissage intéressant.
Il utilise une technique très courante pour la méta-programmation de modèle - une fonction non-modèle couvrant le cas de base et une fonction de modèle qui réduit le problème d'une étape:
// Base case
int count_args() {
return 0;
}
// Reduction
template<typename T, typename... Vs>
int count_args(T _, Vs... vs) {
return 1 + count_args(vs...);
}
Avec cette fonctionnalité en place, vous pouvez implémenter le vérificateur de divisibilité en utilisant l'approche de la réponse de krzaq:
template<int N,typename... Vs>
bool is_arg_divisible(Vs... vs) {
return count_args(vs...) % N == 0;
}