Почему я получаю std :: bad_variant_access с std :: вариантом? - PullRequest
1 голос
/ 15 апреля 2020

Рассмотрим:

#include <variant>
#include <iostream>

int main()
{
    double foo = 666.666;
    std::variant<double, uint64_t> v = foo;
    std::cout << std::get<uint64_t>(v) << std::endl;
    return 0;
}

Это приводит к:

terminate called after throwing an instance of 'std::bad_variant_access'
  what():  Unexpected index
Aborted (core dumped)

Почему?

Я понял, что std::variant будет заменой union , Но если этот базовый c материал терпит неудачу, для чего он хорош?

Ответы [ 2 ]

6 голосов
/ 15 апреля 2020

Я понял, что std :: option будет заменой union.

Да. Вроде. Но ваше недоразумение похоже на союзы в C ++. From cppreference :

Это неопределенное поведение для чтения от члена союза, который не был написан совсем недавно. Многие компиляторы реализуют, в качестве нестандартного расширения языка, возможность чтения неактивных членов объединения.

Обратите внимание, что это отличается от C, который является одной root причиной распространенного недопонимания того, что доступ к неактивному члену также будет разрешен в C ++.

Почему?

Поскольку std::variant имитирует профсоюзы, но добавляет некоторую безопасность и std::get - это ...

Индексный метод доступа к значениям : Если v.index () == I, возвращает ссылку на значение, хранящееся в v. В противном случае выдает std :: bad_variant_access. Вызов некорректен, если I не является допустимым индексом в вариант.

.

Но если этот тип базовых данных c не работает, для чего он нужен?

Союзы в C ++ никогда не предназначались для такого использования. Объединения, скорее, для экономии памяти, когда вы хотите втиснуть два или более значений в одну и ту же память (но в любое время использовать только одно из них). Я никогда не встречал реальных вариантов их использования. std::variant однако, является хорошим дополнением к типам C ++. Более общая картина заключается в том, что уже долгое время существовали так называемые типы продуктов, такие как std::pair<T1,T2>, в том смысле, что набор значений, которые они могут представлять, равен T1 x T2. С std::variantstd::any) теперь C ++ также имеет надлежащие (= со степенью безопасности типов, которую вы никогда не получали от объединений) типов сумм, ie набор значений, которые может представлять std::variant<T1,T2>, равен T1 + T2 ( извините за использование небрежного обозначения, надеюсь, это понятно).

1 голос
/ 15 апреля 2020

std::variant - это «типобезопасное объединение», то есть оно проверит, что то, что вы получаете от него, является типом, который последний раз хранится в нем. В этом примере вы сохраняете double, но пытаетесь получить uint64_t.

См. Документы здесь: https://en.cppreference.com/w/cpp/utility/variant/get

Type- метод доступа на основе значения: если v содержит альтернативу T, возвращает ссылку на значение, хранящееся в v. В противном случае выдает std :: bad_variant_access. Вызов некорректен, если T не является уникальным элементом Types ....

...