#c #c 20 #stdtuple
#c #c 20 #стандартный кортеж
Вопрос:
У меня есть некоторый код, который компилируется и работает нормально под g 10.2.0, но отклоняется clang 11.0.0.
Вот минимальное средство воспроизведения проблемы:
#include <tuple>
#include <cstdint>
struct Dummy { };
using second_t = Dummy;
using example_t = std::tuple<size_t, second_t[8]>;
example_t f() {
example_t resu<
return resu<
}
int main() {
auto x = f();
(void) x;
}
В g он компилируется без жалоб, но с помощью clang я получаю:
clang --std=c 20 -Wall -Werror main.cpp -o example
In file included from main.cpp:1:
/usr/bin/../lib/gcc/aarch64-unknown-linux-gnu/10.2.0/../../../../include/c /10.2.0/tuple:137:4: error: array initializer must be an initializer list
: _M_head_impl(std::forward<_UHead>(__h)) { }
^
/usr/bin/../lib/gcc/aarch64-unknown-linux-gnu/10.2.0/../../../../include/c /10.2.0/tuple:375:9: note: in instantiation of function template specialization 'std::_Head_base<1, Dummy [8], false>::_Head_base<Dummy [8]>' requested here
: _Base(std::forward<_Head>(_M_head(__in))) { }
^
/usr/bin/../lib/gcc/aarch64-unknown-linux-gnu/10.2.0/../../../../include/c /10.2.0/tuple:236:9: note: in instantiation of member function 'std::_Tuple_impl<1, Dummy [8]>::_Tuple_impl' requested here
: _Inherited(std::move(_M_tail(__in))),
^
/usr/bin/../lib/gcc/aarch64-unknown-linux-gnu/10.2.0/../../../../include/c /10.2.0/tuple:996:17: note: in instantiation of member function 'std::_Tuple_impl<0, unsigned long, Dummy [8]>::_Tuple_impl' requested here
constexpr tuple(tupleamp;amp;) = default;
^
main.cpp:11:12: note: in defaulted move constructor for 'std::tuple<unsigned long, Dummy [8]>' first required here
return resu<
^
1 error generated.
make: *** [Makefile:2: all] Error 1
Интересно, что если я изменю second_t
значение на an int32_t
, я тоже получу сообщение об ошибке от g :
g --std=c 20 -Wall -Werror main.cpp -o example
In file included from main.cpp:1:
/usr/include/c /10.2.0/tuple: In instantiation of ‘constexpr std::_Head_base<_Idx, _Head, false>::_Head_base(_UHeadamp;amp;) [with _UHead = int [8]; long unsigned int _Idx = 1; _Head = int [8]]’:
/usr/include/c /10.2.0/tuple:375:49: required from ‘constexpr std::_Tuple_impl<_Idx, _Head>::_Tuple_impl(std::_Tuple_impl<_Idx, _Head>amp;amp;) [with long unsigned int _Idx = 1; _Head = int [8]]’
/usr/include/c /10.2.0/tuple:237:42: required from ‘constexpr std::_Tuple_impl<_Idx, _Head, _Tail ...>::_Tuple_impl(std::_Tuple_impl<_Idx, _Head, _Tail ...>amp;amp;) [with long unsigned int _Idx = 0; _Head = long unsigned int; _Tail = {int [8]}]’
/usr/include/c /10.2.0/tuple:996:17: required from here
/usr/include/c /10.2.0/tuple:137:42: error: array used as initializer
137 | : _M_head_impl(std::forward<_UHead>(__h)) { }
| ^
make: *** [Makefile:2: all] Error 1
Я предполагаю, что это связано с использованием C-массива. Если я изменю код для использования std::array
вместо этого, проблема исчезнет. Тем не менее, мне все еще интересно, есть ли способ сделать это с C-array ради любопытства.
Итак, мои вопросы:
- Был ли g неправ, принимая этот код?
- Есть ли какой-либо способ вернуть C-массив внутри такого кортежа, который работает для g и clang ?
Комментарии:
1. Кошерно ли, согласно стандарту C , иметь простой массив в кортеже — это прекрасный вопрос. Однако, каким бы ни был ответ: это всего лишь одна из тех вещей, которые нецелесообразны, и даже если это правильно, я бы этого не сделал. Если вам нужен массив в кортеже, используйте
std::array
вместо него обычный массив. Вы не заметите другого, и будет меньше неожиданных сюрпризов, с которыми придется иметь дело, и меньше головной боли.2. @SamVarshavchik хотя я согласен, я не могу этого сделать, согласно моему комментарию относительно std::array в вопросе 🙂
3.
std::array
буквальноtemplate <typename T, std::size_t N> struct array { functions; private: T data[N]; };
. Если массив безопасен для вас, то иstd::array
4. я думаю, это потому, что для конструктора копирования / перемещения кортежа :
std::is_move_constructible<Ti>::value must be true for all i, otherwise the behavior is undefined
. Для C-массивов это неверно, поэтому мы получаем неопределенное поведение5. Если вам не нравится
std::array
, вы всегда можете использоватьstruct scared_of_the_STL { second_t data[8]; };
. Это распространено в C, чтобы иметь легко копируемые массивы.
Ответ №1:
Массивы C — это в основном указатели, и обратите внимание, что они не предоставляют и не нуждаются в информации о длине массива. длина должна храниться отдельно и передаваться по кругу. Поэтому одним из способов реализации того, что вам нужно, было бы:
using example_t = std::tuple<size_t, second_t*>;