Можно ли написать шаблон функции, который возвращает, делится ли количество аргументов на N? - программирование
Подтвердить что ты не робот

Можно ли написать шаблон функции, который возвращает, делится ли количество аргументов на N?

Я узнал о вариативных шаблонах и с помощью этого превосходного сообщения в блоге мне удалось написать шаблон функции even_number_of_args, который возвращает независимо от того, делится ли количество аргументов на 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
}

Мне было интересно, можно ли написать шаблон функции, который принимает в качестве аргумента шаблона число N и возвращает ли количество полученных им аргументов кратно N. Например, функция может выглядеть примерно так:

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
4b9b3361

Ответ 1

Да, это так же просто, как

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

В качестве альтернативы вы можете вернуть более удобный для метапрограммирования тип:

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

Ответ 2

Несмотря на то, что решение krzaq довольно хорошо, я считаю, что реализация "волшебства" за sizeof... может служить интересным упражнением для обучения.

Он использует технику, которая очень часто встречается в метапрограмме шаблона - функция без шаблона, охватывающая базовый регистр, и функция шаблона, которая уменьшает проблему на один шаг:

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

Используя эту функциональность, вы можете реализовать проверку делимости, используя подход от ответа krzaq:

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

Демоверсия