gcc和clang在constexpr函数上存在分歧
gcc and clang disagree over constexpr function
从生成器函数中编写一个简单的编译时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++bug)吗?
正如@Casey在评论中正确指出的那样,std::array
或其他聚合的隐式构造函数的constexpr
-性没有任何模糊之处:
12.1建设者[class.ctor]
5默认构造函数,它是默认的,未定义为已删除是在odr使用(3.2)创建的对象时隐式定义的其类类型(1.8),或者在其第一次声明。隐式定义的默认构造函数执行将由用户为该类编写的默认构造函数ctor初始值设定项(12.6.2)和一个空的复合语句。如果用户编写的默认构造函数格式不正确,程序为不正规如果用户编写的默认构造函数满足
constexpr
构造函数(7.1.5)的要求隐式定义的默认构造函数是constexpr
在类的默认默认构造函数是隐式定义的,所有非用户为其基类提供的默认构造函数,以及其非静态数据成员应已隐式定义。[注:隐式声明的默认构造函数具有异常规范(15.4)。显式默认定义可能有隐含的例外说明,请参见8.4--尾注]
这已经在最新的gcc HEAD 5.0.0 20150217中修复,请参阅此实时示例,并且已经在Clang工作了近一年半(自3.4版本IIRC以来,请参阅此问答)。
这里有点雾蒙蒙的。C++14中constexpr的规则禁止(N3797,5.19/2子弹头2)
调用文字类的constexpr构造函数以外的函数、constexpr函数,或隐式调用平凡的析构函数
constexpr
不是类型的一部分,因此传递给make_array_impl
的函数指针不是constexpr函数。另一方面,它引用到constexpr函数,由于这是constexpr求值,编译器必须知道这一点。
然而,Clang支持该代码,并且GCC 4.9没有声称与宽松的constexpr函数一致,所以在这种情况下我会信任Clang。
- C++模板来检查友元函数的存在
- C++quit()函数中可能存在作用域问题
- g++ 说函数不存在,即使包含正确的标头
- C++LinkedList问题.数据类型之间存在冲突?没有匹配的构造函数
- 我知道函数调用中存在歧义.有没有办法调用foo()函数
- 根据某个函数是否存在启用模板
- 尝试根据类中 typedef 的存在来专门化模板函数
- 无论如何,我可以确定构造函数是否存在吗?
- 当覆盖存在时调用基本虚拟"binded to object"函数
- 扩展类中的可选 vir 函数,测试它在运行时是否存在
- C++ 中的函数 GetCursorPos() 和 SetCursorPos() 存在一些问题
- C++ 用于检查容器类中是否存在函数和隐式推导规则的概念
- 当模板重载可用时,检查是否存在函数的自定义重载
- C++'Undefined reference to'错误,尽管包含路径中的头文件中存在函数定义
- 如何使用CPPCHECK查找CPP文件中是否存在函数
- 检查 Linux 库中是否存在函数
- 检查模板类是否存在函数
- 存在函数模板时的参数转换
- 如何检查 C/C++ 中是否存在函数
- 未定义的引用错误,即使存在函数