I am getting spurious errors "non-constant condition" and "use of 'this' in a constant expression" when retrieving the size of a fixed member array, but only from inside class members. The same expression works fine when outside the class member. This is a demo: #include <cstddef> // This is like "sizeof(arr) / sizeof(arr[0])", but with fancy C++. template <typename T, std::size_t N> constexpr std::size_t ArrayElemCount ( T const (&)[N] ) noexcept { return N; } class TestClass { public: int m_array[ 10 ]; void test_method ( void ) const; }; static TestClass test_instance; // This works when checking from outside the class. static_assert( ArrayElemCount( test_instance.m_array ) == 10 ); void TestClass::test_method ( void ) const { // The traditional method still works from inside the class. static_assert( sizeof( m_array ) / sizeof( m_array[0]) == 10 ); // But this fails when checking from inside the class. static_assert( ArrayElemCount( m_array ) == 10 ); // The compilation errors with GCC 14.2 are: // error: non-constant condition for static assertion // static_assert( ArrayElemCount( m_array ) == 10 ); // ~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~ // error: use of 'this' in a constant expression } You can play with it here: https://godbolt.org/z/bYds71fWW
Clang, edg and MSVC all reject it: <source>:29:18: error: static assertion expression is not an integral constant expression 29 | static_assert( ArrayElemCount( m_array ) == 10 ); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ <source>:29:34: note: implicit use of 'this' pointer is only allowed within the evaluation of a call to a 'constexpr' member function 29 | static_assert( ArrayElemCount( m_array ) == 10 ); | ^ GCC is correct here.
This works though: static_assert( std::size( decltype(m_array){} ) == 10 );
even doing: ``` void f(const TestClass *a) { // But this fails when checking from inside the class. static_assert( ArrayElemCount( a->m_array ) == 10 ); } ``` Will fail as `a->m_array ` is NOT a constexpr BUT `test_instance.m_array` is one as the reference to test_instance is one too.
I just found out some more information on this. C++ is counterintuitive here, as template ArrayElemCount is only actually using type information. This article considers it a language defect: https://www.learncpp.com/cpp-tutorial/stdarray-length-and-indexing/ That article mentions that this C++ language issue has been addressed in C++23 by P2280: https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2280r4.html In the meantime, this C++11 implementation should do the trick. It uses a macro as an intermediate step, but I can live with it: https://brnz.org/hbr/?p=1491
So GCC tries to implement p2280r4 (see PR 106650) but maybe not fully after all. Note p2280r4 is considered a fix for a defect too.
clang++ implements p2280 and rejects the test the same. I'm still not sure that there is a bug.
(In reply to Andrew Pinski from comment #3) > even doing: > ``` > void f(const TestClass *a) > { > > // But this fails when checking from inside the class. > static_assert( ArrayElemCount( a->m_array ) == 10 ); > > } > ``` > > Will fail as `a->m_array ` is NOT a constexpr > BUT `test_instance.m_array` is one as the reference to test_instance is one > too. IIUC the accepted revision of P2280 only allows unknown 'this', not pointers to unknown in general.
The original testcase is basically a dup of PR118249, which has recently been fixed for GCC 15, so let's mark this one as a dup *** This bug has been marked as a duplicate of bug 118429 ***
swapped the 2 and 4 in the duplicated bug # :). *** This bug has been marked as a duplicate of bug 118249 ***