gcc和clang对constexpr功能不一致

时间:2015-02-10 16:00:41

标签: c++ gcc clang c++14 constexpr

从生成器函数编写一个简单的编译时std::array工厂,我偶然发现:clang ++ 3.5.1和g ++ 4.9.2不同意函数是否为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 () {}

使用g ++进行编译:

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)... }};

使用clang ++它编译得很好。我可以继续考虑这个有效的g ++ 14(因此g ++有问题吗?)?

2 个答案:

答案 0 :(得分:2)

正如@Casey在评论中正确指出的那样,constexpr或其他聚合的隐式构造函数的std::array - 没有任何模糊之处:

  

12.1构造函数[class.ctor]

     

5默认构造函数,默认为未定义为已删除   当使用odr-used(3.2)创建一个对象时隐式定义   它的类类型(1.8)或者在它之后显式默认的类型   第一次申报。隐式定义的默认构造函数执行   将由a执行的类的初始化集   用户编写的默认构造函数,该类没有   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发布以来,见{{3} }})。

答案 1 :(得分:1)

这有点模糊。禁止在C ++ 14中使用constexpr的规则(N3797,5.19 / 2 bullet 2)

  

为constexpr构造函数调用除文字类,constexpr函数或简单析构函数的隐式调用之外的函数

constexpr不属于该类型,因此传递给make_array_impl的函数指针不是constexpr函数。另一方面,引用到constexpr函数,由于这是constexpr评估,编译器必须知道。

然而,Clang支持该代码,并且GCC 4.9并不声称与轻松的constexpr函数一致,所以在这种情况下我会信任Clang。