2017-10-13 56 views
5

內const int的我有一個配置類未定義的引用shared_ptr的

// config.hpp 

class Config { 
    public: 
    static constexpr int a = 1; 
    static constexpr int b = 1; 
} 

和main.cpp中包括

// main.cpp 
#include "config.hpp" 
int main() { 
    std::cout << Config::a << std::endl; // this is ok 
    std::shared_ptr<otherClass> stream = std::make_shared<otherClass>( 
Config::a); // compile error 
} 

和編譯器說,undefined reference to Config::a

,並使用cout工作時,但在shared_ptr構造函數中不起作用。

我不知道爲什麼會發生這種情況。

+0

你需要像一個靜態成員定義了''在命名空間範圍之前,C++ 17,即'constexpr INT配置::一個;' –

+0

爲什麼' cout'的作品? –

+1

這是完美轉發和odr-usage的不幸後果,使得'make_shared'無法正常工作。 'make_shared (int(Config :: a))'也可以工作 –

回答

7

注意std::make_shared取參數作爲參考,這導致Config::aodr-used因爲它會被綁定到基準參數,則需要其在名字空間範圍定義(C++ 17之前)。

在另一方面,std::cout << Config::a不會造成Config::a被ODR使用的,因爲std::basic_ostream::operator<< (int)取參數由值,Config::a然後經受左值到右值請求的複製初始化參數轉換,因此Config::a是沒有臭味。

如果對象是odr-used,它的定義必須存在。您可以將定義(在實現文件中)添加爲

constexpr int Config::a; // only necessary before C++17 

請注意,它不能有初始值設定項。

LIVE

由於C++ 17 constexpr static data member被隱式直列那麼這樣的定義不再需要,所以你的代碼從C++ 17效果很好。

如果static數據成員被聲明爲constexpr,它是隱含inline,也不需要在命名空間範圍進行重新聲明。沒有初始化程序(以前如上所示需要)的這種重新聲明仍然是允許的,但已被棄用。

LIVE

+0

請注意,名稱空間範圍中的定義不能位於頭文件中;它必須位於與其他所有鏈接的.cpp文件中。 –

1

你一個是私有的,以及一個公衆:需要preceed,或使類結構得到默認公衆。但是,這下編譯C++ 14 https://godbolt.org/g/tS4M1Z

#include <iostream> 
#include <memory> 

struct Config { 
    static constexpr int a = 1; 
    static constexpr int b = 1; 
}; 

struct otherClass { 
    otherClass(int c) { } 
}; 

int main() { 
    std::cout << Config::a << std::endl; // this is ok 
    std::shared_ptr<otherClass> stream = std::make_shared<otherClass>(Config::a); // compile error 
} 
+0

編輯爲公共。對錯誤感到抱歉。 –

+1

是的,這個問題實際上可能與多個翻譯單元有關。如果otherClass的構造函數位於不同的cpp文件中,那麼這在C++ 14中將不起作用。 –