samedi 10 juillet 2021

std::visit can't deduce type of std::variant

My purpose is getting any value from the data array without specifying the type every time when I'm getting the value. I created special tables that describes the field information (field name and type) and also wrote a function that helps me to interpret data properly.

The code is presented below:

#include <iostream>
#include <variant>
#include <assert.h>
#include <string_view>
#include <unordered_map>

enum class ValueType : uint8_t
{
    Undefined       = 0x00,
    Uint32,
    AsciiString,
};

typedef uint64_t FieldId;

struct FieldInfo
{
    std::string _name;
    ValueType _type;
};

typedef std::unordered_map<FieldId, FieldInfo> FieldContainer;

static FieldContainer requestFields =
{
    { 0, { "user-id",   ValueType::Uint32, } },
    { 1, { "group-id",  ValueType::Uint32, } },
};

std::variant<uint8_t, uint32_t, std::string_view> getValue(ValueType type,
                                                           const uint8_t* data,
                                                           size_t length)
{
    if (type == ValueType::Uint32)
    {
        assert(length == sizeof(uint32_t));
        return *reinterpret_cast<const uint32_t*>(data);
    }
    else if (type == ValueType::AsciiString)
    {
        return std::string_view(reinterpret_cast<const char*>(data), length);
    }

    return static_cast<uint8_t>(0);
}


int main(int argc, char *argv[])
{
    const uint8_t arr[] = {0x00, 0x11, 0x22, 0x33};
    size_t length = sizeof(arr);

    const auto value = getValue(ValueType::Uint32, arr, length);

    std::visit([](auto&& arg)
                    {
                        if ( arg == 0x33221100 )
                        {
                            std::cout << "Value has been found" << std::endl;
                        }
                    }, value);
    return 0;
}

I expect that the compiler would deduce the return value properly and let me do the numbers comparing. However, I received the following compiler messages:

error: no match for ‘operator==’ (operand types are ‘const std::basic_string_view<char>’ and ‘int’)
   57 |                         if ( arg == 0x33221100 )
      |                              ~~~~^~~~~~~~~~~~~

error: invalid conversion from ‘int’ to ‘const char*’ [-fpermissive]
   57 |                         if ( arg == 0x33221100 )
      |                                     ^~~~~~~~~~
      |                                     |
      |                                     int

I know that I can get value via calling std::get:

    if ( std::get<uint32_t>(value) == 0x33221100 )
    {
        std::cout << "Value has been found" << std::endl;;
    }

But it is not what I want to achieve.

The question is - can I use the presented approach to get a value without specifying the type in each place of code where I need that?

Environment info:

  • OS: Linux
  • Compiler: g++ (GCC) 11.1.0
  • Standard: C++17

Aucun commentaire:

Enregistrer un commentaire