Please refer to this snippet:
#include <type_traits>
#include <string_view>
constexpr std::size_t strlen(char const* s) {
std::size_t n = 0;
while (*s++ != '\0')
++n;
return n;
}
template <std::size_t>
struct X {};
int main() {
constexpr auto pf = __PRETTY_FUNCTION__; // gcc ok; clang ok; (1)
static_assert(std::string_view(__PRETTY_FUNCTION__) == std::string_view("int main()")); // gcc ok; clang ok; (2)
X<strlen(__PRETTY_FUNCTION__)> x; // gcc not ok; clang ok; (3)
}
Clang 8 compiles it, but GCC 8.3 dos not. See on godbolt. GCC fails on line (3)
although lines (1)
and (2)
are ok.
If I am able to declare pf
in line (1)
and use __PRETTY_FUNCTION__
in static_assert
it means that the expression __PRETTY_FUNCTION__
is core constant expression. And if I'm not able do declare X<strlen(__PRETTY_FUNCTION__)> x
it means that strlen(__PRETTY_FUNCTION__)
is not an integral constant expression.
So why strlen(__PRETTY_FUNCTION__)
is not an integral constant expression? Is it implied by the standard, or is it a GCC bug?
__PRETTY_FUNCTION__ is a gcc extension that is mostly the same as __FUNCTION__, except that for C++ functions it contains the "pretty" name of the function including the signature of the function. Visual C++ has a similar (but not quite identical) extension, __FUNCSIG__.
Constant expression. Literal constant expression is a prvalue core constant expression of non-pointer literal type (after conversions as required by context). A literal constant expression of array or class type requires that each subobject is initialized with a constant expression.
Constant expression. A constant expression is either. a glvalue core constant expression that refers to. an object with static storage duration that is not a temporary, or. an object with static storage duration that is a temporary, but whose value satisfies the constraints for prvalues below, or.
A function is needed for constant evaluation if it is a constexpr function and named by an expression that is potentially constant evaluated.
__PRETTY_FUNCTION__
is not standard. As such a compiler can implement it in different places (while parsing, while building the AST or while linking).
If it's supposed to be implemented while parsing, then it can be a constant expression (I guess that's what clang is doing). However, if it's implemented while linking (that is, the compiler emits a symbol for it and the linker will resolve it), it can't be a constant expression.
I think GCC use the latter case.
Please notice that you can take a sizeof() of these in that case, since it's a const char[]
if you need compile-time constant string's length computation.
So replace expression 3 by:
X<sizeof(__PRETTY_FUNCTION__) - 1> x;
and it'll compile fine on both compiler.
EDIT: As NathanOliver pointed out, it seems that GCC consider the signature of __PRETTY_FUNCTION__
as static const char[]
while clang/visual studio consider it as static constexpr const char[]
. This is a painful nuisance in GCC (not a bug, since it's not standard) and they seems to have fixed it in the >8.0.0 version.
In expression (1) and expression (2), __PRETTY_FUNCTION__
is decayed to a const char*
(the pointer are constant, but nothing can be said about the data). For me, expression (2) might not prove anything, since there is no guarantee the pointers should be equal on both side of the equality, even if they points to the "same" content. string_view
constructor expects const char*
, thus anything other than __PRETTY_FUNCTION__
that could decay to const char*
would pass expression (2).
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