2016-06-18 88 views
1

假設我有一個模板類,像這樣:終止模板搜索

template<typename T, const T* array> 
struct NullTArrayLength{ 
    static constexpr size_t value = NullTArrayLength<T, array+1>::value; 
}; 

/* Some how have a specialization that terminates on when array[0] = 0 */ 

這樣做的目的是爲了找到0結束的數組的長度它將被用來像這樣:

constexpr char array[] = "this is a test"; 
constexpr size_t length = NullTArrayLength<char,array>::value; 

問題是我無法終止模板搜索。

通常我會專門的模板來終止搜索,但我看不出這樣做在這裏。

那麼你如何專門化這樣的模板?

+0

如何使用'std :: array '? –

+0

@πάνταῥεῖ我不能這樣做,因爲我不希望在字符串長度類型(即有違有一個神奇的模板獲取字符串的長度的點,所以我沒有這樣做) – DarthRubik

+1

這有更高的目的嗎?你不能只使用sizeof(數組)? – md5i

回答

1

代碼中的主要問題不是終止模板遞歸,而是array + 1不是有效的模板非類型參數,如標準中[14.3.2]中所述。對於C++ 11和14,這樣的說法必須具有特定的形式,&ID-表達,可能省略&。在C++ 14之後,需求已經被放寬並且以常量表達式的更新規則來表示,但是仍然參數不能是子對象的地址;這排除了任何指針算術,因爲它是根據子對象的地址定義的。

如果你堅持使用基於類模板(不是我的第一選擇,見下文)的解決方案,可以解決通過避免模板參數指針運算;這裏有一個辦法做到這一點,包括檢查結束模板遞歸:

#include <iostream> 
#include <cstddef> 

template<const char* P, std::size_t I = 0, char = P[I]> struct len 
{ 
    static constexpr std::size_t value = len<P, I + 1>::value + 1; 
}; 

template<const char* P, std::size_t I> struct len<P, I, 0> 
{ 
    static constexpr std::size_t value = 0; 
}; 

constexpr char a[] = "this is a test"; 

int main() 
{ 
    constexpr auto s = len<a>::value; 
    std::cout << s << '\n'; 
} 

爲清楚起見,我用char的元素類型,因爲這是你在找什麼,據我瞭解。該解決方案顯然可以擴展到可以是非類型模板參數類型的任何T。對於不能直接傳遞的T,最後一個模板參數可以是bool,它接收調用確定結束條件的constexpr謂詞的結果。

然而,一個更簡單,更清晰的解決方案涉及基本實現在constexpr功能strlen;只要它是一個常量表達式,即使在C++ 11中,也可以使用這樣的調用表達式作爲模板參數。對於C++ 14,它是如此簡單:

#include <iostream> 
#include <cstddef> 

constexpr std::size_t const_len(const char* p) 
{ 
    std::size_t i = 0; 
    while(p[i] != 0) ++i; 
    return i; 
} 

extern constexpr char a[] = "this is a test"; 

int main() 
{ 
    constexpr auto s = const_len(a); 
    std::cout << s << '\n'; 
} 

與C++ 11條constexpr遵守規則遞歸溶液同樣很簡單。