Путаница при выводе из std:: кортеж, не может обрабатывать std:: get
Моя основная идея состояла в том, чтобы вывести мой собственный класс из std:: tuple, чтобы получить некоторые вспомогательные типы внутри, как это:
template <typename ... T>
class TypeContainer: public std::tuple<T...>
{
public:
using BaseType = std::tuple<T...>;
static const size_t Size = sizeof...(T);
TypeContainer(T... args):std::tuple<T...>(args...){};
using index_sequence = std::index_sequence_for<T...>;
};
Теперь я пытаюсь использовать код следующим образом:
using MyType_tuple_with_empty = std::tuple< std::tuple<float,int>, std::tuple<>, std::tuple<int>>;
using MyType_typecontainer_with_empty = TypeContainer< TypeContainer<float,int>, TypeContainer<>, TypeContainer<int>>;
using MyType_tuple_non_empty = std::tuple< std::tuple<float,int>, std::tuple<int>, std::tuple<int>>;
using MyType_typecontainer_non_empty = TypeContainer< TypeContainer<float,int>, TypeContainer<int>, TypeContainer<int>>;
template <typename T>
void Do( const T& parms )
{
// The following lines result in errors if TypeContainer with
// empty element comes in. The empty element is in std::get<1> which
// is NOT accessed here!
std::cout << std::get<0>(std::get<0>(parms)) << " ";
std::cout << std::get<1>(std::get<0>(parms)) << std::endl;
std::cout << std::get<0>(std::get<2>(parms)) << std::endl;
}
int main()
{
MyType_tuple_with_empty p1{{ 1.2,3},{},{1}};
Do( p1 );
MyType_typecontainer_with_empty p2{{ 1.2,3},{},{1}};
Do( p2 ); // << this line raise the error
MyType_tuple_non_empty p3{{ 1.2,3},{4},{1}};
Do( p3 );
MyType_typecontainer_non_empty p4{{ 1.2,3},{4},{1}};
Do( p4 );
}
Если я компилирую с Do(p2)
, я получаю следующую ошибку:
Может ли кто-нибудь объяснить, почему существование пустогоОшибка: нет соответствующей функции для вызова '
get(const TypeContainer<TypeContainer<float, int>, TypeContainer<>, TypeContainer<int> >&)
'
TypeContainer
в связи с std::get
приведет к этой проблеме?
Править: Дополнительная информация:
В строки
MyType_tuple_with_empty p1{{{ 1.2,3},{},{1}}};
MyType_tuple_non_empty p3{{ 1.2,3},{4},{1}};
Может быть скомпилирован не с gcc5. 2. 0, а с gcc6.1.0. Это немного загадочно, потому что я помню, что конструктор кортежа действительно явный. Почему это работает с gcc6.1.0? Но это не та проблема, которую я ищу: -)
Еще один намек: Код, с которым у меня возникли проблемы, похоже, компилируется с clang3. 5. 0.
Немного трудно понять...
Edit2: Копаясь в списках ошибок (длинный: -)) я нашел:
/опт/Линукс-gnu_5.2.0/включать/с++/5.2.0/кортеж|832 коль 5| Примечание: аргумент шаблона вычета/замещения не: главный.cpp / 104 col 45 / Примечание: '
std::tuple<_Elements ...>
' является неоднозначным базовым классом 'TypeContainer<TypeContainer<float, int>, TypeContainer<>, TypeContainer<int> >
' ||std::cout << std::get<0>(std::get<0>(parms)) << " "
;
Похоже, что в libg++ кто-то извлекает несколько раз из любого типа кортежа, который кажется сломанной библиотекой. Поиск по этой теме приводит меня к следующему: ошибка пустых вложенных кортежей
Это действительно связано? Тот же баг или новый: -)
1 ответ:
К сожалению, вам придется добавить свои контейнерные версии функций get:
template <std::size_t I, typename ...T> decltype(auto) get(TypeContainer<T...>&& v) { return std::get<I>(static_cast<std::tuple<T...>&&>(v)); } template <std::size_t I, typename ...T> decltype(auto) get(TypeContainer<T...>& v) { return std::get<I>(static_cast<std::tuple<T...>&>(v)); } template <std::size_t I, typename ...T> decltype(auto) get(TypeContainer<T...> const& v) { return std::get<I>(static_cast<std::tuple<T...> const&>(v)); }
И просто использовать
get
Неstd::get
вDo
вид функций. Компилятор может выбрать пространство имен из аргументов.Я думаю, я не уверен, что это потому, что gcc имеет EBO - пустую базовую оптимизацию - реализованную в своих кортежах. Какова именно причина, догадаться довольно трудно. Вы можете сообщить об этом в gcc bugzilla.
Кстати, это не очень хорошая привычка производные от классов STD. Если бы вы начали с компиляции, а не наследования, то вам нужно было бы предоставить свои собственные функции
get
, и вы не заметили бы этой ошибки, экономя, вероятно, много времени.