Gcc and clang disagree with constexpr function

Having written a simple compilation time std::array factory from a generator function, I came across this: clang ++ 3.5.1 and g ++ 4.9.2 do not agree whether the function is constexpr or not.

Code (this is 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 () {} 

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

With clang ++, it compiles just fine. Can I continue to review this valid g ++ 14 (and therefore g ++ listening)?

+6
source share
2 answers

As @Casey correctly noted in the comments, there is nothing obscure in the constexpr -ness of the implicit constructor std::array or other aggregates:

12.1 Constructors [class.ctor]

5 The default constructor, which by default is not defined as remote, is implicitly defined when odr (3.2) is used to create an object of its class type (1.8) or when it is explicitly defaulted after its first declaration. An implicit default constructor executes a set of class initializations, which will be performed using the user default constructor for this class without the ctor-initializer (12.6.2) and an empty compound statement. If this default custom constructor is poorly formed, the program is poorly formed. If this custom default constructor satisfies the requirements of the constexpr constructor (7.1.5), an implicitly defined default constructor is constexpr . . the standard default constructor for a class is implicitly defined; all default default constructors for base classes and its non-static data members must be implicitly defined. [Note: An implicitly declared default constructor has an exception specification (15.4). An explicit default definition may have an implicit exception, see 8.4. -end note]

This has been fixed in the latest gcc HEAD 5.0.0 20150217 release, see this live example and has been working in Clang for almost a year and a half (since the release of IIRC 3.4, see this Q & A ).

+2
source

It is a bit foggy. Rules for constexpr in C ++ 14 prohibit (N3797, 5.19 / 2 bullet 2)

calling a function other than the constexpr constructor for the literal class, a constexpr function, or an implicit trivial destructor call

constexpr not part of the type, so the function pointer passed to make_array_impl is not a constexpr function. On the other hand, this refers to the constexpr function, and since it is a constexpr evaluation, the compiler should know this.

However, Clang supports this code, and GCC 4.9 does not require matching with relaxed constexpr functions, so I would trust Clang in this case.

+1
source

Source: https://habr.com/ru/post/982281/


All Articles