2017-10-07 66 views
1

當前我正在閱讀Scott Meyers的Effective Modern C++項目15 - 儘可能使用constexpr。)。作者說:當編譯時不知道參數時,不調用`constexpr`構造函數

當constexpr函數被調用與被 不是在編譯期間已知的一個或多個值,它就像一個正常的功能, 計算其在運行時的結果。這意味着您不需要兩個函數來執行相同的操作,一個用於編譯時間 常量,另一個用於所有其他值。 constexpr函數全部都是 。

我嘗試了下面的代碼片段在http://coliru.stacked-crooked.com/

#include <iostream> 

class Point 
{ 
    public: 
     constexpr Point(double a, double b) noexcept 
      : _a(a), _b(b) 
     { 
     } 

     void print() const noexcept 
     { 
      std::cout << "a -> " << _a << "\tb -> " << _b << std::endl; 
     } 

    private: 
     double _a; 
     double _b; 
}; 

double get_a() noexcept 
{ 
    return 5.5; 
} 

double get_b() noexcept 
{ 
    return 5.6; 
} 


int main() 
{ 
    constexpr Point p1(2.3, 4.4); 
    p1.print(); 
    int a = get_a(); 
    int b = get_b(); 
    constexpr Point p2(a, b); 
    p2.print(); 
    return 0; 
} 

在創建p1對象一切如預期的情況:參數被稱爲編譯時和成員被正確初始化。在創建p2對象的情況下,儘管在編譯時我們不知道ab變量的值,但它應該在我的理解中起作用,因爲構造函數應該充當正常函數。但我發現了以下錯誤信息:

main.cpp: In function 'int main()' 
main.cpp:38:28: error: the value of 'a' is not usable in a constant expression 
    constexpr Point p2(a, b); 
          ^
main.cpp:36:9: note: 'int a' is not const 
    int a = get_a(); 
     ^
main.cpp:38:28: error: the value of 'b' is not usable in a constant expression 
    constexpr Point p2(a, b); 
          ^
main.cpp:37:9: note: 'int b' is not const 
    int b = get_b(); 

Coliru使用GCC編譯器。 所以,我不明白是什麼問題。也許我錯過了什麼......

+1

你不應該申報'p2'爲'constexpr',因爲它不能。所以只要'點p2(a,b);''''' – songyuanyao

+0

爲什麼?在'p1'中,成員初始化編譯時間,因爲我們有編譯時間的已知參數:2.3,4.4。在'p2'情況下,我們不知道'a'和'b'編譯時間的值,並不意味着成員應該已經初始化了運行時? (當一個constexpr函數被調用時,有一個或多個在編譯期間未知的值,它就像一個普通函數,在運行時計算其結果。) –

+1

您的報價僅指函數。如果你聲明一個對象或表達式'constexpr',你需要在編譯時進行評估,而'p2'不能像宋玉瑤指出的那樣。 – patatahooligan

回答

6

cppreference(重點煤礦)

一個constexpr變量必須滿足以下要求:

  • 它的類型必須爲LiteralType
  • 必須立即初始化
  • 初始化充分表達,包括所有隱式轉換,構造函數的調用等,必須是一個常量表達式

在你的榜樣?

constexpr Point p2(a, b); 

... ab不是常量表達式。爲了使他們常量表達式,你需要標記get_aget_ba,並且bconstexpr

constexpr double get_a() noexcept 
{ 
    return 5.5; 
} 

constexpr double get_b() noexcept 
{ 
    return 5.6; 
} 

constexpr int a = get_a(); 
constexpr int b = get_b(); 
constexpr Point p2(a, b); 
4

你誤會斯科特的解釋:他並不意味着你可以做constexpr具有非常量數據的對象。這樣的結構不應該工作

constexpr Point p2(a, b); 

,因爲編譯器不知道的ab值,所以你不能申報編譯器,你p2對象constexpr

他的意思是,當你定義一個constexpr函數或成員函數,這樣

int constexpr foo(int a, int b) { 
    return 2*a + b; 
} 

這顯然工作時,ab是編譯時間常數,但它會繼續甚至工作時ab是變量:

cout << foo(2, 5) << endl; // This obviously works 
int a, b; 
cin >> a >> b; 
cout << foo(a, b) << endl; // This works too 

Demo.

在你的情況下,它意味着您可以繼續撥打Point的,即使變量構造函數,但你不能結果迫使constexpr

Point p2(a, b); // This works, even though Point(int,int) is constexpr 
+0

在我的情況下'a'和'b'不是變量? –

+0

其實問題在於我把'p2'聲明爲'constexpr'。 –

+1

@DavidHovsepyan絕對,他們是。這意味着你可以將它們傳遞給'constexpr'函數,但這並不意味着函數結果也會變爲'constexpr'。你不能在'p2'上強制'constexpr',這是'constexpr'函數調用變量的結果。 – dasblinkenlight

相關問題