簡體   English   中英

非積分常數

[英]non-integral constants

我想要一個帶有非整數常量的頭文件,例如一個類。 注意常數並不需要是一個編譯時間常數。

static const std::string Ten = "10";

這編譯但不可取,因為每個編譯單元現在都有自己的Ten副本。

const std::string Ten = "10";

這將編譯但會因為多重定義的Ten的鏈接器錯誤而失敗。

constexpr std::string Ten = "10"s;

這可以工作,但前提是字符串構造函數也是constexpr。 它會但是我不能指望每個非整數常量都有一個constexpr構造函數......或者我可以嗎?

extern const std::string Ten = "10";

這似乎有效,但我擔心如果我錯誤地呼吸,我會收到鏈接器錯誤。

inline const std::string Ten( ) { return "10"; }

這有我想要的一切,除了干凈的語法。 另外,現在我必須將常量稱為函數調用Ten()

inline const std::string = "10";

這似乎是理想的解決方案。 當然,標准不允許使用inline變量。

  • c ++標准中是否有一些內容表明外部版本應該有用,或者我很幸運它與GCC一起使用?
  • 是否有令人信服的理由不允許內聯變量?
  • c ++ 03有更好的方法還是c ++ 0x會有更好的方法?

你好像混淆了他們。

你是對的

static const std::string Ten = "10"; 

版。 它將“工作”,但它將在每個翻譯單元中創建一個單獨的對象。

沒有static的版本將具有相同的效果。 不會產生鏈接器錯誤,但會在每個轉換單元中定義一個單獨的對象。 在C ++語言中, const對象默認具有內部鏈接,這意味着

const std::string Ten = "10"; // `static` is optional

static的先前版本完全等效。

帶有extern和初始化程序的版本

extern const std::string Ten = "10"; // it's a definition!

會產生與外部連接的對象的定義 (這是一個定義,因為一個初始化的存在)。 版本將導致鏈接器錯誤,因為您將最終得到具有外部鏈接的對象的多個定義 - 違反ODR。

這是你如何做到的:

為了實現您想要實現的目標,您必須在頭文件中聲明您的常量

extern const std::string Ten; // non-defining declaration

然后在一個且只有一個實現文件中定義它(使用初始化程序)

extern const std::string Ten = "10"; // definition, `extern` optional

(如果常量被預先聲明為extern ,那么定義中的extern是可選的。即使沒有顯式的extern它也會定義一個帶有外部鏈接的const對象。)

我不知道C ++中是否有更好的方法,但C中最好的方法(也適用於C ++)是你列出的方法之一。

有一個單獨的編譯單元(例如, ten.cpp )只保存數據:

const std::string Ten = "10";

和一個頭文件(例如, ten.h )聲明它,以便它可以在別處使用:

extern const std::string Ten;

然后你必須確保任何想要使用它的編譯單元包括頭文件(例如, ten.h ),並且任何想要使用它的可執行文件鏈接到單獨的編譯單元(例如, ten.o )。

這為您提供了變量的一個副本,可在任何地方訪問。 當然,您可以在頭文件中將其定義為靜態,並為每個編譯單元創建一個副本。 這將簡化您需要的文件,靜態將確保沒有雙重定義的符號。 但這不是我推薦過的。

我不知道你為什么說:

但是,如果我錯誤地呼吸,我恐怕會收到鏈接器錯誤

這是很久以前的公認實踐,如果你想稱自己為C ++程序員(沒有任何侮辱),你應該知道所有這些東西是如何組合在一起的。

extern版本接近你想要的。 這里:

// in the file tenconstant.cpp
const std::string Ten = "10";

// in the file tenconstant.h
extern const std::string Ten;

// in your file
#include "tenconstant.h"

// do stuff with Ten

你需要為鏈接器定義一次,這是myconstants.cpp的目的,但是在你使用它的任何地方聲明,這是myconstants.h的目的。 對於一個變量來說,這看起來有點笨拙,但是對於一個更大的項目,你可能會有一個很好的標題,可以使用很多,你可以堅持這個。

以這種方式創建靜態用戶定義類型是一個壞主意。 當您有多個此類UDT時,無法控制實例化的順序。 這在小型項目中不是問題,但並非所有項目都很小。 最好的做法是將靜態數據作為所有普通的舊數據類型 - 原始指針 - 並以適當的方式初始化它們,以指向程序啟動時所需的實例,或者何時需要它們。 這讓你掌控一切。

您的問題表明這些類型不需要是編譯時常量。 如果是這樣,並且您有一個多線程程序,則您的對象需要保護其狀態不受多個線程的同時訪問。 如果某些對象不是線程安全的,那么除了對象本身之外,還需要一個互斥對象來保護其狀態,並且必須具有相同的鏈接,並且需要初始化。 所有這些使得程序的全局狀態變得復雜,這可能是一種不可接受的方式。

我認為這里的其他答案更好,但如果您使用標題完成所有操作,您可以使用簡單的包裝函數有效地inline您的對象(正如您特別要求的那樣)。

inline const std::string &get_ten() {
    static const std::string ten = "10";
    return ten;
}

將只有一個string ,初始化一次,並且您不需要頭文件之外的任何內容。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM