2016-06-08 48 views
4

下面的代碼如何正確工作?「不完整」對象實例化和輸出行爲

#include <cstdio> 

template<class T> 
T x = T{}; 

void foo() 
{ 
    class Test 
    { 
    public: 
     Test() { std::printf("Test::Test\n"); } 
    }; 

    Test t = x<Test>; 
} 


int main() 
{ 
    std::printf("main\n"); 
} 

輸出

Test::Test 
main 

Live example

  • 爲什麼它打印Test::Test第一,而不是main
  • 它依賴哪個標準?僅僅是C++ 1z嗎?我無法找到相關的提案。你能給我一個鏈接嗎?
  • 什麼是x在這段代碼和Test t = x<Test>如何實際工作?

而且,如果我改變std::printf調用std::cout整個程序崩潰:

#include <iostream> 

template<class T> 
T x = T{}; 

void foo() 
{ 
    class Test 
    { 
    public: 
     Test() { std::cout << "Test::Test\n"; } 
    }; 

    Test t = x<Test>; 
} 


int main() 
{ 
    std::cout << "main\n"; 
} 

輸出

Segmentation fault  (core dumped) ./a.out 

Live example

爲什麼?

+0

Google「變量模板」。 –

+0

@sleep緊pup Ok好的,謝謝。爲什麼它實例化沒有調用'foo'函數呢? – FrozenHeart

+0

[tmp.inst/5](http://eel.is/c++draft/temp#variable%20template!definition~of):「除非顯式實例化或明確指定了可變模板專門化,否則可變模板當專業化被使用時,專業化被隱含地實例化「 –

回答

3

正如其他人已經提到的,你使用了一個可變模板。

如果我沒有記錯,可變模板類似於這樣的事情:

template<class T> 
struct X { 
    static T x; 
}; 

template<class T> 
T X<T>::x = T{}; 

那麼您可以使用它,這將是這樣的:

void foo() { 
    class Test { 
    public: 
     Test() { std::printf("Test::Test\n"); } 
    }; 

    Test t = X<Test>::x; 
} 

如果你試試這個,你會看到相同的結果:coliru

該模板在foo中實例化,並且發出初始化靜態成員的代碼。 這個初始化發生在main運行之前,所以你首先打印Test::Test

至於初始化,儘管其中的變量用於從不被調用的代碼發生的事情 - 我編譯器可以嘗試推理foo從來沒有被稱爲在整個程序中,Test是一個本地類,其類型不逃脫foo,因此使實例X<Test>::x無法爲其他人,並決定刪除它...

......但我想這將需要一些努力在鏈接時,我看不到這種行爲強制要求標準。

此外,我不確定如果編譯器/鏈接器甚至允許刪除非局部變量的初始化,如果該初始化有副作用。