2014-08-28 65 views
1

我有這樣的代碼如何使用元編程過濾常量類型和非常量類型?

#include <iostream> 

size_t F() 
{ 
     return 0; 
} 

template <class Type, class... NextTypes> 
size_t F(const Type& type, const NextTypes&... nextTypes) 
{ 
     if (!std::is_const<Type>::value) 
       return sizeof(type) + F(nextTypes...); 
     else 
       return F(nextTypes...); 
} 

int main() 
{ 
    int a = 0; 
    const int b = 0; 
    const size_t size = F(a,b); 
    std::cout << "size = " << size << std::endl; 
    return 0; 
} 

我想在編譯時間知道的常量參數和非const的參數的總規模。目前放出來是8,由於某種原因,編譯器認爲b不是恆定的,我用typeiddecltype打印類型的ab乃至輸出顯示bint,而不是const int如我所料。我錯過了什麼?是否可以將一組可變參數分隔爲常量參數和非常量?

回答

6

考慮這個函數模板:

template<typename T> 
void deduce(const T&); 

如果你讓編譯器推斷出類型T從參數表達式,推導型絕不會const:它會嘗試使函數參數的const T與用於調用函數的參數表達式的類型相同。例如:

struct cls {}; 
const cls c; 

deduce(c) // deduces T == cls 

通過推導T == cls,編譯器成功地使const T相同參數類型const cls。編譯器沒有理由爲const和非const參數類型生成兩個不同的函數;在任何情況下,函數模板實例化的參數類型都將被const限定:您通過請求const T&而不是T&


您可以推斷出通過參數的常量性不 CV-修飾函數參數:

template<typename T> 
void deduce(T&); 

然而,這將無法綁定到非const臨時對象(右值) 。爲了支持他們,以及,你可以使用普遍引用

template<typename T> 
void deduce(T&&); 

如果參數是一個左值,並沒有提及如果該參數是右值這將演繹出一個左值引用類型T。這個常量將被正確地推導出來。

例如,如果參數的類型爲const A並且是左值,則T將推導爲const A&。函數參數然後是const A& &&,它摺疊爲const A&(左值參考)。如果參數是一個右值,則T將推導爲const A,函數參數將變爲const A&&(右值參考)。

請注意,因爲T可以作爲參考,所以在檢查常量之前需要刪除它:std::is_const< typename std::remove_reference<T>::type >::value

+0

*「編譯器沒有理由爲const和非const參數類型生成兩個不同的函數」*這只是一個猜測。我不知道實際的基本原理。 – dyp 2014-08-28 18:22:25