2016-09-30 99 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

相關問題