Miałem kilka pytań dotyczących nowego typu STD :: wariant. Uważałem się za stosowanie go jako alternatywy dla Union. Napisałem jakiś kod testowy, który powinien skompilować w kompilatorze online. Nie znalazłem wielu informacji dotyczących przechowywania typów takich jak STD :: tablarek w STD :: Wariant. Surowe przechowywanie buforów (np. E.G UINT8_T [4]) nie wydaje się być możliwe dzięki wariantowi STD ::.

#include <iostream>
#include <array>
#include <variant>
#include <array>
#include <stdint.h>
#include <typeinfo>
#include <cstdlib>
using parameters_t = std::variant<uint32_t, std::array<uint8_t, 4>>;

void setComParams(parameters_t& comParameters_, uint8_t value);

int main()
{
    std::array<uint8_t, 4> test;
    parameters_t comParameters = test; // can I assign the array here directly in some way?
    auto parametersArray = std::get_if<std::array<uint8_t, 4>>(&comParameters);
    if(parametersArray == nullptr) {
        exit(0);
    }

    auto & parameterReference1 = *parametersArray; //so I can use [] indexing
    parameterReference1[1] = 5;
    parameterReference1[3] = 6;
    std::cout << "I should be 5: " << (int)(*parametersArray)[1] << std::endl;
    std::cout << "I should be 5: " << (int)parameterReference1[1] << std::endl;
    std::cout << "I should be 6: " << (int)(*parametersArray)[3] << std::endl;
    std::cout << "I should be 6: " << (int)parameterReference1[3] << std::endl;
    setComParams(comParameters, 10);
    std::cout << "I should be 10: "<< (int)(*parametersArray)[1] << std::endl;
    std::cout << "I should be 10: "<< (int)parameterReference1[1] << std::endl;

    comParameters = 16; // this should be an uint32_t now
    auto parametersArray2 = std::get_if<std::array<uint8_t, 4>>(&comParameters);
    if(parametersArray2 == nullptr) {
        std::cout << "Everything in order" << std::endl;
    }

    uint32_t * parameterNumber = std::get_if<0>(&comParameters); // using index now
    *parameterNumber = 20;
    std::cout << "I should be 20: "<< (int)*parameterNumber << std::endl;
    setComParams(comParameters,30);
    std::cout << "I should be 30: "<< (int)*parameterNumber << std::endl;
    return 0;
}

void setComParams(parameters_t &comParameters_, uint8_t value) {
    auto comParametersArray = std::get_if<std::array<uint8_t, 4>>(&comParameters_);
    if(comParametersArray == nullptr) {
        auto comParameterValue = std::get_if<uint32_t>(&comParameters_);
        if(comParameterValue != nullptr) {
            *comParameterValue = value;
        }
    }
    else {
        auto & arrayReference = *comParametersArray;
        arrayReference[1] = value;
    }
}

Aby mieć pewność, że zrozumiałem wszystko poprawnie: jeśli użyłem STD :: Get, zawsze otrzymuję kopię, co oznacza, że nie ma znaczenia, jak to robię, nie mogę modyfikować rzeczywistej wartości wariantu. Czy zawsze muszę używać STD :: Get_if w tej sprawie? Ponadto, czy istnieje jakikolwiek znaczący kod lub nad głową przy użyciu STD :: wariant w porównaniu z związkami? Zwłaszcza, że zasadniczo używam typów POD (związek UINT32_T i UINT8_T [4]).

Z góry dziękuję.

0
Spacefish 21 marzec 2020, 18:05

1 odpowiedź

Najlepsza odpowiedź

Możesz przypisać / zainicjować std::variant bezpośrednio z prvalue of typ, który chcesz Emiplaci:

parameters_t comParameters = std::array<uint8_t, 4>{};

Chociaż ten zero - inicjuje tablicę w przeciwieństwie do kodu.

Jeśli chcesz uniknąć konstrukcji kopiowania / ruchu, możesz użyć

parameters_t comParameters(std::in_place_type<std::array<uint8_t, 4>>);

Do inicjalizacji lub.

comParameters.emplace<std::array<uint8_t, 4>>();

Do zadania.

Jednak nadal zero zainicjowanie std::array. O ile mi wiadomo, obecnie nie ma możliwości domyślnego zainicjowania obiektu w std::variant.

std::get_if Zwraca wskaźnik do obiektu w std::variant. Nigdy nie tworzy kopii obiektu.

Zamiast std::get_if, można również użyć std::get. std::get Właśnie wyrzuci wyjątek, jeśli spróbujesz uzyskać dostęp do niewłaściwego typu i zwraca referencje do zawieranego obiektu. Nigdy też nie kopiuje obiektu.:

auto& parameterReference1 = std::get<std::array<uint8_t, 4>>(comParameters);

Wbudowane typy tablic lub typów odniesienia lub typy funkcji nie są dozwolone w liście typu std::variant, ponieważ typy są wymagane do zaspokojenia koncepcji niszczenia, co oznacza, że wyrażenie

t.~T()

Gdzie t jest typu T musi być dobrze uformowany. Nie jest to prawdą dla wbudowanych tablic, ale dla prawie wszystkich innych rozsądnych typów obiektów.

2
walnut 21 marzec 2020, 15:45