2015-02-10 91 views
6

寫一個簡單的編譯時間std::array工廠從一個生成器函數,我偶然發現:鏗鏘++ 3.5.1和g ++ 4.9.2不同意函數是否是constexpr或不。gcc和clang不同意constexpr函數

的代碼(這是C++ 14!):

#include <array> 
#include <utility> 

    template <class T, std::size_t N, class GenType, std::size_t... I> 
    constexpr std::array<T, N> 
make_array_impl (GenType gen, std::index_sequence <I...>) 
{ 
    return {{ gen (I)... }}; 
} 

    template <class T, std::size_t N, class GenType> 
    constexpr std::array<T, N> 
make_array (GenType gen) 
{ 
    return make_array_impl <T, N> (
      gen, 
      std::make_index_sequence <N> {} 
    ); 
} 

    constexpr int 
generator_const (std::size_t /* index */) 
{ 
    return 1; 
} 

    constexpr auto 
a = make_array <int, 3> (generator_const); 

static_assert (a.size() == 3, ""); 
static_assert (a[0] == 1, ""); 
static_assert (a[1] == 1, ""); 
static_assert (a[2] == 1, ""); 

int main() {} 

與克++編譯:

migou ~ % g++ -std=c++14 ex.cpp 
ex.cpp:28:41: in constexpr expansion of ‘make_array<int, 3ul, int (*)(long unsigned int)>(generator_const)’ 
ex.cpp:18:5: in constexpr expansion of ‘make_array_impl<int, 3ul, int (*)(long unsigned int), {0ul, 1ul, 2ul}>(gen, (std::make_index_sequence<3ul>{}, std::make_index_sequence<3ul>()))’ 
ex.cpp:8:21: error: expression ‘generator_const’ does not designate a constexpr function 
return {{ gen (I)... }}; 

隨着鐺++它編譯就好了。我可以繼續考慮這個有效的g ++ 14(因此g ++ bug)嗎?

+2

'g ++'在['g ++'version __5__](https://gcc.gnu.org/projects/cxx1y.html)放寬了'constexpr'的要求,所以也許就是這個原因。 'clang'已經在3.4版本中實現了N3638。 – Zeta 2015-02-10 16:11:21

回答

2

如@Casey正確地評價所指出的,沒有什麼霧關於constexpr -ness的std::array或其他聚集體的隱式構造的:

12.1的構造[class.ctor]

5默認構造函數是默認構造函數,當它被odr-used(3.2)創建其類類型(1.8)的對象時,或者在它的之後顯式默認3210首次申報。隱式定義的默認構造函數執行 該類的初始化集,該類將由 用戶編寫的該類的默認構造函數執行,該類沒有 ctor-initializer(12.6.2)和空的複合語句。如果用戶編寫的默認構造函數 不合格,則該程序爲 不合格。 如果該用戶編寫的默認構造函數滿足constexpr構造函數(7.1.5)的 要求,則隱式定義的默認構造函數爲constexpr在默認構造函數的默認構造函數 被隱式定義之前,所有其基類的非用戶提供的默認構造函數和其非靜態數據成員都應被隱式定義。 [注意: 隱式聲明的默認構造函數具有 異常規範(15.4)。明確默認的定義 可能有一個隱含的異常規定,見8.4。 - 注意]

這已在最新的gcc HEAD 5.0中修復。0 20150217,請參閱此live example,並且自從近一年半以來一直在Clang工作(自3.4版本IIRC以來,請參閱this Q&A)。

+0

有問題的部分是函數指針'gen',而不是數組構造函數。 – 2015-02-18 12:43:56

+0

@SebastianRedl爲什麼會有問題? – TemplateRex 2015-02-18 12:45:45

1

這是有點霧。在C++ 14禁止不(N3797,5.19/2子彈2)

比constexpr構造爲一個文字類,一個constexpr功能,或其中的一個隱式調用其它的函數的調用爲constexpr規則瑣碎析

constexpr是不是類型的一部分,所以傳遞給make_array_impl函數指針不是constexpr功能。另一方面,它指定爲一個constexpr函數,並且由於這是constexpr評估,所以編譯器必須知道這一點。

但是,Clang支持該代碼,並且GCC 4.9並不聲稱與寬鬆的constexpr函數一致,所以在這種情況下我會信任Clang。

+0

此項目符號所指的調用可以是隱式的。這就是說我相信這個電話應該沒問題。 – Columbo 2015-02-10 16:58:13

+0

我不認爲對寬鬆'constexpr'的支持是一個問題。被調用的函數*是一個'constexpr'函數,所以它應該完全符合C++ 11'constexpr'規則。事實上,[clang和g ++在C++ 11模式下編譯這個簡化的測試用例時沒有任何診斷](http://coliru.stacked-crooked.com/a/85af35047baa4386)。我懷疑這是一個g ++的錯誤。 – Casey 2015-02-10 19:45:10

+0

查看我對標準報價的回答,爲什麼不應該懷疑OP代碼中的所有內容都是真正的「constexpr」。 – TemplateRex 2015-02-18 12:19:40