2014-12-02 17 views
1

當我嘗試編譯下面包含的代碼時,我注意到了一個奇怪的行爲。我有4個文件如下編譯器錯誤或正確的行爲爲靜態const成員變量,variadic模板和&&?

createshared.h:

#ifndef CREATESHARED_H_ 
#define CREATESHARED_H_ 

#include <memory> 
#include <utility> 

#ifdef USE_REFREF 
template<typename T, typename... Args> 
std::shared_ptr<T> create_shared(Args&&... args) 
{ 
    class HelperClass : public T 
    { 
    public: 
     HelperClass (Args&& ... nargs) : T(std::forward<Args...>(nargs)...) {} 
     virtual ~HelperClass() = default; 
    }; 

    return std::make_shared<HelperClass>(std::forward<Args...>(args)...); 
} 
#else 
template<typename T, typename... Args> 
std::shared_ptr<T> create_shared(Args... args) 
{ 
    class HelperClass : public T 
    { 
    public: 
     HelperClass (Args ... nargs) : T(nargs...) {} 
     virtual ~HelperClass() = default; 
    }; 

    return std::make_shared<HelperClass>(args...); 
} 
#endif 

#endif 

staticinitclass.h

#ifndef STATICINITCLASS_H_ 
#define STATICINITCLASS_H_ 

class StaticInitClass 
{ 
public: 
#ifdef INITIALIZE_IN_HEADER 
    static const int default_i = 1; 
#else 
    static const int default_i; 
#endif 
    virtual ~StaticInitClass() = default; 
    StaticInitClass() = delete; 
protected: 
    StaticInitClass(int i); 
}; 

#endif 

staticinitclass.cpp:

#include "staticinitclass.h" 

#include <iostream> 

#ifndef INITIALIZE_IN_HEADER 
const int StaticInitClass::default_i = 2; 
#endif 

StaticInitClass::StaticInitClass(int i) 
{ 
    std::cout << "Created with " << i << std::endl; 
} 

的main.cpp:

#include "staticinitclass.h" 
#include "createshared.h" 
#include <memory> 

int main(int argc, const char* argv[]) 
{ 
    auto shared = create_shared<StaticInitClass>(StaticInitClass::default_i); 
} 

沒有標誌,程序編譯並運行正常。

$ g++ -std=c++11 main.cpp staticinitclass.cpp 
$ ./a.out 
Created with 2 

精細,因爲default_i是不可或缺的類型,我們可以在頭初始化。讓我們做到這一點

$ g++ -std=c++11 main.cpp staticinitclass.cpp -DINITIALIZE_IN_HEADER 
$ ./a.out 
Created with 1 

好,還是編譯並運行良好。現在,讓我們添加& &和std ::向前

$ g++ -std=c++11 main.cpp staticinitclass.cpp -DINITIALIZE_IN_HEADER -DUSE_REFREF 
/tmp/cc3G4tjc.o: In function `main': 
main.cpp:(.text+0xaf): undefined reference to `StaticInitClass::default_i' 
collect2: error: ld returned 1 exit status 

連接錯誤。好了,現在讓我們來嘗試初始化我們default_i成員在.cpp

$ g++ -std=c++11 main.cpp staticinitclass.cpp -DUSE_REFREF 
$ ./a.out 
Created with 2 

它再次工作。使用clang會得到相同的結果,這會導致我相信這不僅僅是一個孤立的編譯器錯誤,而可能是語言本身阻止靜態初始化的一些東西。我似乎無法連接爲什麼加入& &會導致休息。

目前我使用在Ubuntu 14.04

任何想法G ++ 4.8.2和鐺++ 3.5使用-DINITIALIZE_IN_HEADER和-DUSE_REFREF當這到底是怎麼壞了?

+0

爲靜態數據成員提供初始化並不意味着您也提供了一個定義。當你結合兩個'-D'選項時,你最終會使用這個靜態成員的odr,因此需要爲它提供一個定義。 – Praetorian 2014-12-02 20:46:25

回答

2

繼§9.4.2[class.static.data]:

如果非易失性const的靜態數據成員是整型或枚舉類型的,其在類定義聲明可以指定一個括號或等於初始值設定項,其中每個作爲賦值表達式的初始化子句都是一個常量表達式(5.19)。 [...] 如果程序中odr-used(3.2)並且名稱空間作用域定義不包含初始值設定項,成員仍應在名稱空間作用域中定義。

換句話說,給一個const靜態數據成員直接在頭中的值並不意味着你不需要定義該數據成員。你應該在staticinitclass中有這個。CPP文件:

#ifndef INITIALIZE_IN_HEADER 
const int StaticInitClass::default_i = 2; 
#else 
const int StaticInitClass::default_i; // this is what you don't have 
#endif 

綁定到一個參考(以推導爲const左值引用轉發引用&&你的情況)算作這個數據成員的ODR使用

如果你沒有使用轉發引用,並且你的參數的值是,那麼它不是該靜態數據成員的odr使用,因此不會引發鏈接器錯誤。

+0

缺少的部分是僅僅使用該值不算作odr用途。 – 2014-12-02 21:00:46

+0

@ T.C。加上這個以及 – 2014-12-02 21:07:55

+0

啊!我完全不知道odr使用的規範。謝謝! – ilektron 2014-12-03 18:59:19

相關問題