2015-02-10 93 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