2014-09-30 132 views
2

我讀了下面的類型允許作爲非類型模板參數:使用左值參考作爲非類型模板參數

  • 整型
  • 枚舉
  • PTR到對象/方法
  • 左值參考對象/方法
  • 的std :: nullptr_t

我不明白如何非常量指針或左值引用是可以接受的?它們不應該是常量類型,以便在編譯時識別它們嗎?

很顯然,我並不比標準更聰明所以有人告訴我一個左參考的例子,也許被用作非模板參數的指針?

+0

這是可能的,因爲對象一定會存在,並且編譯器知道在它會存在的地址。因此,在你的程序中對它的引用進行硬編碼幾乎沒有什麼意義。 – 2014-09-30 15:43:28

+1

沒有「非模板參數」這樣的東西。你正在考慮「非類型模板參數」。 (編輯:謊言,腳註137(n3337)中有一個這樣的短語,但這是非規範性文本)。 – jrok 2014-09-30 15:46:40

+0

爲什麼你認爲左值參考不可接受? – texasbruce 2014-09-30 15:49:04

回答

4

下面是同時具有一個方法指針和一個左值引用作爲非類型模板參數的一個示例:

int delete_counter_1 = 0; 
int delete_counter_2 = 0; 

template<int& ctr> 
void increment_counter() { ++ctr; } 

template<void(*func)()> 
class Deleter { 
    public: 
    ~Deleter() { func(); } 
}; 

int main() { 
    { /* Internal scope */ 
     Deleter<increment_counter<delete_counter_1>> a, b; 
     Deleter<increment_counter<delete_counter_2>> c; 
    } 
    std::cout << "Counter1: " << delete_counter_1 
       << "; Counter2: " << delete_counter_2 
       << '\n'; 
    return 0; 
} 

查看它coliru

關於Deleter類有趣的是,它沒有實際的數據成員;它的析構函數可以直接內聯而不需要間接的函數調用。

如在評論中提及由DALIBOR Frivaldsky,所述的一點是,(實例化)功能delete_counter<int&>和本身具有固定在編譯時已知地址計數器,所以作爲指針它們的值是恆定的。特別是,這僅適用於具有靜態壽命的對象;自動(「堆棧分配」)對象將不起作用,並且非靜態類成員,但靜態對象(如上)和靜態類成員都不錯。

+0

基於部分OP的問題:「我不明白如何一個非常量指針或左值引用是否可以接受?它們不應該是常量類型,以便它們在編譯時被識別嗎?「,我認爲還值得注意的是,非類型模板參數與常量無關類型,但在編譯時知道對象的地址。這就是爲什麼引用和指向結構或類成員(但不是成員函數!)的指針不能用作非類型模板參數的原因。這就是爲什麼你可以使用「delete_counter_1」或者2 - 它們總是有相同的地址 – 2014-09-30 16:21:20

+0

@DaliborFrivaldsky:非靜態類成員。靜態類成員很好,afaik。 g ++ - 4.8也堅持兩個刪除計數器都有外部連接,但是clang與內部連接沒問題;我需要找出爲什麼g ++ - 4.8認爲外部鏈接是必要的。 – rici 2014-09-30 16:27:26

+0

真實,重要的細節 - 非靜態類成員 – 2014-09-30 16:29:15

0

標準解釋很清楚在14.3.2 [temp.arg.nontype]什麼可以用來作爲一個參數,如果一個非類型模板參數是一個指針或引用:

  • 常量表達式(5.19),其指定的地址包括函數 模板和函數模板id,但不包括非靜態類成員,表達(忽略括號) as & id-expression,具有靜態存儲持續時間的完整對象 以及外部或內部鏈接或具有外部或內部鏈接的函數。在哪裏-expression是一個對象或函數的名稱,不同的是 &可以省略如果名稱是指功能或陣列,並且如果相應的 模板參數是一個參考將被省略;或
  • 一個常量表達式,其值爲一個空指針值(4.10);或
  • 一個常量表達式,其值爲空成員指針值(4.11);或
  • 指向成員的指針,如5.3所述。1;或
  • 型STD的常量表達式:: nullptr_t