2016-09-30 80 views
46

我一直在学习可变参数模板,并与this excellent blog post的帮助下,我已经成功地编写一个函数模板even_number_of_args它返回它接收参数个数是否整除2是否可以编写一个函数模板来返回参数个数是否可​​以被N整除?

#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 

回答

70

是的,就这么简单

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 {}; 
} 
+0

一般FYI:返回值是一个编译时间常量。 – iammilind

+2

'std :: integral_constant '在我看来是更好的返回类型。 :) – Yakk

+0

我认为对于不熟悉C++元编程习语的人来说可能会更困惑一些。不过,我会将其作为替代方式进行编辑。 – krzaq

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...); 
} 

利用这种功能在地方,你可以使用这种方法从krzaq的答案实现整除检查:

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

Demo.

+3

我相信'sizeof ...''必须使用比你提到的技巧更少的“compliation”循环。因此,为了学习的目的,总是建议使用'sizeof ...'。 :-) – iammilind

+3

我想补充一点,这也是函数式编程的基础:提供一个基本案例,并使另一个案例依赖于递归。 –

+1

这会生成模板实例化递归。编译器可以自由限制这一点,一般在1000左右。像'sizeof ...'这样的内置函数,或者甚至在一些编译器'make_index_sequence '上绕过这个限制,并且更好的启动性能。你可以用一堆工作来实现日志深度'make_index_sequence'甚至可能'is_arg_divisible':上面的模式充其量只是学习和小案例的玩具模式(不适合图书馆),即使你遇到问题没有内置。 – Yakk

相关问题