Хорошо, вот код:
#include <cstdio>
#include <cstdint>
template<typename T>
[[nodiscard]] constexpr bool
run_tests() noexcept
{
T const blah1[6]{4, 8, 15, 16, 23, 42};
T const blah2[6]{4, 8, 15, 16, 23, 42};
T const blah3[6]{};
if (__builtin_memcmp(blah1, blah2, 6 * sizeof(T)) != 0) {
return false;
}
if (__builtin_memcmp(blah1, blah3, 6 * sizeof(T)) == 0) {
return false;
}
return true;
}
int
main() noexcept
{
static_assert(run_tests<int8_t>());
// static_assert(run_tests<int64_t>());
if (run_tests<int8_t>()) {
printf("success\n");
}
else {
printf("failure\n");
}
if (run_tests<int64_t>()) {
printf("success\n");
}
else {
printf("failure\n");
}
return 0;
}
С Clang 10 (на Windows), это прекрасно компилируется, и если я его запускаю, я получаю:
success
success
Как я и ожидал. Если я раскомментирую следующее:
static_assert(run_tests<int64_t>());
, я получаю следующую ошибку во время компиляции:
error: static_assert expression is not an integral constant expression
Здесь есть две странные вещи. Во-первых, это нормально компилируется с int8_t
и uint8_t
, но любой другой целочисленный тип, который я предоставляю, воспроизводит ошибку выше. Во-вторых, если я закомментирую это:
if (__builtin_memcmp(blah1, blah3, 6 * sizeof(T)) == 0) {
return false;
}
Он прекрасно компилируется и со всеми целочисленными типами. Так что это только тот случай, когда массивы не равны и не являются 8-битными, что я получаю эту ошибку во время компиляции.
Мысли? Мне это кажется ошибкой, но я хотел посмотреть, что думают другие, прежде чем я отправлю отчет об ошибке. Для справки я попытался скомпилировать с включенными C ++ 17 и C ++ 20, и я убедился, что Clang 10 реализует __builtin_memcmp в качестве constexpr (как с помощью макроса __has, так и благодаря тому, что он прекрасно компилируется как constexpr в какой-то сценарий ios).