Writting a simple compile time std::array
factory from a generator function, I stumbled upon this: clang++ 3.5.1 and g++ 4.9.2 disagree on whether a function is constexpr
or not.
The 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 go on and consider this valid g++14 (and thus g++ bugged)?
With some benchmarks, it is seen that lld is faster than ld and even the newer ld-gold. Build tool – Perhaps another place where Clang Vs GCC difference comes to the forefront. GCC uses autotools and Make as its build tools whereas Clang/LLVM uses CMake as its build tool.
Code complexity – GCC is a very complicated software with more than 15 million lines of code. Although it has well-defined frontend/backend stages, the software in itself is more monolithic in nature. Let us now see how Clang Vs GCC would look.
Clang/LLVM is a compiler toolchain that supports C, C++, and Objective-C natively. This sentence does not justify the power of Clang/LLVM. To understand why I rave about this compiler toolchain, I need to describe a bit more about how the modern compiler architecture looks like: Clang/LLVM is a textbook case of such an architecture.
As can be seen from the name Clang supports mostly C, C++, and Objective-C. But the framework underlying Clang called LLVM is extensible enough to support newer languages like Julia and Swift. From the perspective of C++, both are excellent compilers supporting the C++17 standard.
As @Casey correctly pointed out in the comments, there is nothing foggy about the constexpr
-ness of the implicit constructor of std::array
or other aggregates:
12.1 Constructors [class.ctor]
5 A default constructor that is defaulted and not defined as deleted is implicitly defined when it is odr-used (3.2) to create an object of its class type (1.8) or when it is explicitly defaulted after its first declaration. The implicitly-defined default constructor performs the set of initializations of the class that would be performed by a user-written default constructor for that class with no ctor-initializer (12.6.2) and an empty compound-statement. If that user-written default constructor would be ill-formed, the program is ill-formed. If that user-written default constructor would satisfy the requirements of a
constexpr
constructor (7.1.5), the implicitly-defined default constructor isconstexpr
. Before the defaulted default constructor for a class is implicitly defined, all the non-user-provided default constructors for its base classes and its nonstatic data members shall have been implicitly defined. [ Note: An implicitly-declared default constructor has an exception-specification (15.4). An explicitly-defaulted definition might have an implicit exceptionspecification, see 8.4. —end note ]
This has been fixed in the latest gcc HEAD 5.0.0 20150217, see this live example, and has been working in Clang since almost a year and a half now (since the 3.4 release IIRC, see this Q&A).
This is kinda foggy. The rules for constexpr in C++14 forbid (N3797, 5.19/2 bullet 2)
an invocation of a function other than a constexpr constructor for a literal class, a constexpr function, or an implicit invocation of a trivial destructor
constexpr
is not part of the type, so the function pointer passed to make_array_impl
is not a constexpr function. On the other hand, it refers to a constexpr function, and since this is constexpr evaluation, the compiler has to know that.
However, Clang supports that code, and GCC 4.9 doesn't claim conformance with relaxed constexpr functions, so I would trust Clang in this case.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With