簡體   English   中英

constexpr和ODR

[英]constexpr and ODR

如果我們有一個頭文件widget.hpp ,其內容如下:

constexpr int foo = 10;

struct widget
{
    int bars[foo];
};

...我們有兩個源文件生成的兩個翻譯單元,它們都只包含widget.hpp ,這是否違反了一個定義規則(更具體地說, foo的使用是否違反了一個定義規則)?

foo具有內部鏈接,但它也是一個常量表達式。 從我在C ++ 11標准中閱讀3.2.6(我將在下面引用)中可以看出,如果需求#2不僅僅指靜態數據成員,那么它就是格式良好的。


3.2.6要求#2:

在D的每個定義中,根據3.4查找的相應名稱,應指在D的定義中定義的實體,或者在重載決議(13.3)之后和部分模板專業化匹配之后應引用同一實體(14.8) .3), 除非名稱可以引用具有內部鏈接或沒有鏈接的非易失性const對象,如果該對象在D的所有定義中具有相同的文字類型,並且該對象使用常量表達式(5.19)初始化,並且該對象沒有使用odr,並且該對象在D的所有定義中具有相同的值

我可以看到任何關於你的案件的任何空間的唯一地方是你對foo的使用是否有資格作為odr-used或不使用。 或許至少澄清意圖的最簡單的方法是引用n1337的相應部分(緊接着官方標准,主要是清理一些措辭,例如在這種情況下):

[...]如果對象在D的所有定義中具有相同的文字類型,並且該對象使用常量表達式(5.19)和值(但是該值)初始化,則名稱可以引用具有內部鏈接或無鏈接的const對象使用對象的地址),並且對象在D的所有定義中具有相同的值;

您的使用明顯符合所有這些要求。

  1. foo在每種情況下都有int類型。
  2. foo用常量表達式初始化。
  3. 你只使用foo的值,而不是地址。
  4. foowidget所有定義中具有相同的值。

也就是說,你可能最好將foos改為std::vector而不是:

struct widget { 
    std::vector<int> bars;

    widget : bars(foo) {}
};

至於foo的多個定義,我不認為foo是odr-used,因為它滿足出現在常量表達式中的要求,如3.2.3所示:

除非x是滿足出現在常量表達式中的要求的對象,否則其名稱顯示為可能已評估的表達式ex的變量x將被使用。

因此,因為它沒有使用odr規則不適用於它,3.2.4:

每個程序應該只包含該程序中使用的每個非內聯函數或變量的一個定義

至於widget的兩個不同定義,以及它們是否與3.2.6完全相似。 答案是肯定的,因為N3485 3.2.6:

如果對象在D的所有定義中具有相同的文字類型[yes,both int],並且對象被初始化,則名稱可以引用const對象[yes,constexpr是const],內部[constexpr是內部]或沒有鏈接使用常量表達式[yes,10],並使用對象的值(但不是地址),並且對象在D的所有定義中具有相同的值[yes,10]

因此,即使名稱foo指的是兩個不同TU中的兩個不同實體,這兩個實體也滿足給定的要求。

(實際上它的工作原理是因為編譯器會以相同的方式布局這兩個類,因此來自兩個TU的生成代碼將是兼容的。)

我不明白你的解釋。 引用的文本適用於引用的示例。 只要你在所有TU中都包含它。 要違反ODR,您必須破壞文本的某些內容:

constexpr double foo = 10; // type
constexpr int foo = ret_10(); // non-const init
constexpr int foo = 42; // value

並打破ODR使用我認為你必須采取其地址。

暫無
暫無

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

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