#include<Python.h>intmain()
{
int array[] = {1, 2, 3};
returnPy_ARRAY_LENGTH(array);
}
Building this example with g++ -std=gnu++11 example.cpp or just g++ example.cpp fails with:
In file included from Include/Python.h:70,
from x.cpp:1:
x.cpp: In function ‘int main()’:
Include/pymacro.h:217:30: error: ‘__builtin_types_compatible_p’ was not declared in this scope
217 | + Py_BUILD_ASSERT_EXPR(!__builtin_types_compatible_p(typeof(array), \
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~
The example builds correctly if I use -std=c++11 (g++ -std=c++11 example.cpp).
changed the title [-]C API: Py_ARRAY_LENGTH() macro is incompatible with g++ -std=gnu++11[/-][+][C API] Py_ARRAY_LENGTH() macro is incompatible with g++ -std=gnu++11[/+]on Oct 4, 2026
@da-woods: It would be nice to be able to use __builtin_types_compatible_p() on C++ when it's supported. The problem is that I don't know how to check if the built-in function is available or not.
(...) which does imply you shouldn't be using it in c++
Well well well, a simple fix is to do exactly that: don't use __builtin_types_compatible_p() on C++. I implemented this approach in PR gh-158812.
Other places in the code base use _Py__has_builtin, but I don't think this buys us much here, since we know __builtin_types_compatible_p isn't supported in C++. Yet, it'll reduce the detection to #if _Py__has_builtin(__builtin_types_compatible_p).
The most natural fit in modern C++ beginning with C++17 is std::size, and AI will for sure spit out something for earlier versions, but that's all template based, and you've mentioned in #157649 (comment) that templates did not play out nicely for Py_CLEAR et al.
The example builds correctly if I use -std=c++11 (g++ -std=c++11 example.cpp).
When using -std=c++11, the __STRICT_ANSI__ macro is defined. In this case, Py_ARRAY_LENGTH() doesn't use built-in functions (it doesn't use __builtin_types_compatible_p() or typeof()).
Other places in the code base use _Py__has_builtin, but I don't think this buys us much here, since we know __builtin_types_compatible_p isn't supported in C++. Yet, it'll reduce the detection to #if _Py__has_builtin(__builtin_types_compatible_p).
__has_builtin(typeof) and __has_builtin(__builtin_types_compatible_p) are false using -std=c++11 and -std=gnu++11. So it cannot be used in C++ for Py_ARRAY_LENGTH().
The most natural fit in modern C++ beginning with C++17 is std::size, and AI will for sure spit out something for earlier versions, but that's all template based, and you've mentioned in #157649 (comment) that templates did not play out nicely for Py_CLEAR et al.
I'm sure that it's possible to write something nice using templates, but I would prefer to keep the Python C API simple, and avoid C++ templates in general.
#define Py_ARRAY_LENGTH(array) (sizeof(array) / sizeof((array)[0])) works just fine on C++.
It's just that it doesn't detect API misuse on C++. It would be nice to have, but it's ok to not detect API misuse in this case.
I just merged my PR to just use #define Py_ARRAY_LENGTH(array) (sizeof(array) / sizeof((array)[0])) in C++.
Activity
da-woods commented on Oct 4, 2026
The documentation for __builtin_types_compatible_p says
Which leaves a mystery about why it seems to work in -std=c++11 but which does imply you shouldn't be using it in c++
pythongh-158810: Fix Py_ARRAY_LENGTH() macro on C++
vstinner commented on Oct 4, 2026
@da-woods: It would be nice to be able to use __builtin_types_compatible_p() on C++ when it's supported. The problem is that I don't know how to check if the built-in function is available or not.
Well well well, a simple fix is to do exactly that: don't use __builtin_types_compatible_p() on C++. I implemented this approach in PR gh-158812.
chris-eibl commented on Oct 5, 2026
Other places in the code base use _Py__has_builtin, but I don't think this buys us much here, since we know __builtin_types_compatible_p isn't supported in C++. Yet, it'll reduce the detection to #if _Py__has_builtin(__builtin_types_compatible_p).
The most natural fit in modern C++ beginning with C++17 is std::size, and AI will for sure spit out something for earlier versions, but that's all template based, and you've mentioned in #157649 (comment) that templates did not play out nicely for Py_CLEAR et al.
gh-158810: Fix Py_ARRAY_LENGTH() macro on C++ (#158812)
vstinner commented on Oct 5, 2026
When using -std=c++11, the __STRICT_ANSI__ macro is defined. In this case, Py_ARRAY_LENGTH() doesn't use built-in functions (it doesn't use __builtin_types_compatible_p() or typeof()).
__has_builtin(typeof) and __has_builtin(__builtin_types_compatible_p) are false using -std=c++11 and -std=gnu++11. So it cannot be used in C++ for Py_ARRAY_LENGTH().
I'm sure that it's possible to write something nice using templates, but I would prefer to keep the Python C API simple, and avoid C++ templates in general.
#define Py_ARRAY_LENGTH(array) (sizeof(array) / sizeof((array)[0])) works just fine on C++.
It's just that it doesn't detect API misuse on C++. It would be nice to have, but it's ok to not detect API misuse in this case.
I just merged my PR to just use #define Py_ARRAY_LENGTH(array) (sizeof(array) / sizeof((array)[0])) in C++.
Thanks for your feedback @da-woods and @chris-eibl.
gh-158810: Use _Py_TYPEOF in Py_ARRAY_LENGTH() (#158838)
[3.15] gh-158810: Fix Py_ARRAY_LENGTH() macro on C++ (#159315)
[3.14] gh-158810: Fix Py_ARRAY_LENGTH() macro on C++ (#159317)