web-dev-qa-db-ja.com

引数の数が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
46
mwhittaker

はい、それはと同じくらい簡単です

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 {};
}
70
krzaq

Krzaqのソリューションは非常に優れていますが、sizeof...の背後にある「魔法」を実装することは、興味深い学習課題になると思います。

これは、テンプレートメタプログラミングに非常に一般的な手法を使用します。基本的なケースをカバーする非テンプレート関数と、問題を1ステップ減らすテンプレート関数です。

// 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;
}

デモ

27
dasblinkenlight