是否有可能编写一个函数模板来返回参数的数量是否可以被N整除?

mwh*_*ker 46 c++ variadic-templates c++11

我一直在学习可变参数模板,在这篇优秀博客文章的帮助下,我设法编写了一个函数模板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
}
Run Code Online (Sandbox Code Playgroud)

我想知道是否有可能编写一个函数模板,它接受一个数字作为模板参数,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
Run Code Online (Sandbox Code Playgroud)

krz*_*zaq 70

是的,它很简单

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

或者,您可以返回更友好的元编程类型:

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

  • 在我看来,`std :: integral_constant <bool,sizeof ...(Ts)%N == 0>`将是一个更好的返回类型.:) (2认同)
  • 对于C++ 11的兼容性,将返回类型放在`auto`和`return {};`(你的版本是C++ 14)中.还可以使用4个字符.;) (2认同)

das*_*ght 27

尽管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...);
}
Run Code Online (Sandbox Code Playgroud)

有了这个功能,你可以使用krzaq的答案来实现divisibility checker:

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

演示.

  • 我相信`sizeof ...`必须使用较少的"compliation"循环,与你提到的技巧相比.因此,即使出于学习目的,也总是建议使用`sizeof ...`.:-) (3认同)
  • 我想补充一点,这也是函数式编程的基础:提供一个基本案例,并使另一个案例依赖递归到它. (3认同)