2017-09-08 102 views
3

下面的代碼編譯失敗:Constexpr成員函數

// template<class> 
struct S { 
    int g() const { 
     return 0; 
    } 

    constexpr int f() const { 
     return g(); 
    } 
}; 

int main() 
{ 
    S /*<int>*/ s; 
    auto z = s.f(); 
} 

GCC,例如,抱怨:錯誤:調用非constexpr函數 '的int ::克()const的' 。這是完全合理的。但如果我將S放入模板中,代碼將編譯(使用MSVC 15.3,GCC 7.1.0,clang 4.0.1進行檢查)。

爲什麼? constexpr在類模板中有什麼特殊含義?

據我瞭解,這段代碼是不正確的,但標準並不要求編譯器產生錯誤(爲什麼?)。

+0

一方面,有趣的行爲。另一方面,爲什麼從constexpr函數中調用一個非constexpr函數呢? – AndyG

+0

@AndyG這只是一個簡單的例子。在我的情況下,'S'是一個模板類,根據模板參數從不同的基類派生。 'g()'在基類中。然後我做了''()''constexpr',並且只在_some_基類('constexpr'ness有意義)中創建了'g()''constexpr'。當'S'由非'constexpr'' g()'派生的基類時,我感到困惑,因此沒有發現編譯器錯誤。因此,這個問題。 – Evgeny

+1

最好是,因爲我們希望能夠擁有一個模板類,這個模板類可能是constexpr的方法,這取決於它的模板參數,也可能不是。我不知道這個標準在哪裏是允許的。 – Yakk

回答

1

每[dcl.constexpr]

The definition of a constexpr function shall satisfy the following constraints:
...
every constructor call and implicit conversion used in initializing the return value (6.6.3, 8.5) shall be one of those allowed in a constant expression

g()到的呼叫中不允許一常量表達式。每[expr.const]:

A conditional-expression is a core constant expression unless it involves one of the following as a potentially evaluated subexpression...:
— an invocation of a function other than [...] a constexpr function

它看起來像一些編譯器可能允許你這樣做,你在做什麼,因爲z未聲明constexpr因此該值不需要在被稱爲編譯時。如果你改變你的代碼

constexpr auto z = s.f(); 

你會看到所有這些編譯器將進行BARF,模板或沒有。

+0

零甚至可以用'getchar()'來代替。 – Evgeny

+0

來自[cppreference.com](http://en.cppreference.com/w/cpp/language/constexpr):_A'constexpr'函數必須滿足以下要求:...至少存在一組參數值,使得函數的調用可以是核心常量表達式的一個評估子表達式(對於構造函數,在常量初始化器中使用就足夠了)(自C++ 14以來)。違反此項目要求不需要診斷。問題是,爲什麼不需要診斷? – Evgeny

+0

@Evgeny:很好地捕捉到無需診斷的方面。通常的解釋是,執行某些事情要麼花費太多時間,要麼不可能爲所有輸入做。 – AndyG