-1

I'am new in cpp. Let's say we've got a class as follows:

 class Animal {
    public:
        enum class Group {mammal, bird, reptile};
    private:    
        Group group;
}

Now I'd like to initialise it in this way:

Animal::Group g;
std::cin >> g;
std::unique_ptr<Animal> dog = std::make_unique<Animal>(std::move(g));

I tried to overload istream as below and make it friend of class Animal but it doesn't work.

auto string_to_vlt(std::string const s) -> std::optional<Human::Violation>
{
    if (s == "mammal")     return Animal::Group::mammal;
    if (s == "bird")       return Animal::Group::bird;
    if (s == "reptile")    return Animal::Group::reptile;
    return std::nullopt;
}

auto operator>>(std::istream& is, Animal::Group v) -> std::istream& // friend function
{
    auto s = std::string();
    if (!(is >> s)) {
        return is;
    }
    if (auto result = string_to_vlt(s)) {
        v = *result;
    }
    return is;
}

Any ideas? Is it possible at all?

Caparso
  • 39
  • 5
  • 2
    "_but it doesn't work._": How does it not work? `Animal::Group v`: That's taking the argument by-value. Do you really want that? Also, what value do you expect `g` to have if `auto result = string_to_vlt(s)` causes the `else` branch to be taken? Also, `std::move` move on an enumeration type does absolutely nothing and `Animal` can't be constructed from a `Group` the way you defined it. So `std::make_unique(std::move(g))` should fail to compile. – user17732522 Aug 03 '23 at 15:36
  • I am not sure it is conceptually correct but I think yes I do. My intention is to give a user the option to initialise it by typing the group of animal. That's the first thing which come to my mind. Is it wrong? There is no fail in compilation – Caparso Aug 03 '23 at 15:42
  • 1
    This is where a [`std::map`](https://en.cppreference.com/w/cpp/container/map) mapping table could come in handy. Try to steer away from "piles of `if` statements" as a problem solving method. – tadman Aug 03 '23 at 15:43
  • 4
    You are calling the `operator>>` overload with `std::cin >> g;` and it seems that you intent the function to modify the value of `g`. But you are passing `g` _by-value_. So you are just modifying a copy of `g` in `operator>>`. If you want to modify `g` in that line, then you'll need _pass-by-reference_. – user17732522 Aug 03 '23 at 15:44
  • 2
    There's not much point passing `v` __by value__ to `operator>>`. You want to pass a _reference_ if you want your assignment to do anything useful. – Toby Speight Aug 03 '23 at 15:49
  • 3
    Probably also a good idea to set the failbit of the stream if conversion is unsuccessful, too. – Toby Speight Aug 03 '23 at 15:50
  • @tadman Would please tell me how can I use std::map to handle it? – Caparso Aug 03 '23 at 16:00
  • @user17732522 thanks, u are right, I missed that point. I added & and it works now. Btw, now I see ostream is overloaded correct as I use it to visualise a value of the class member :) – Caparso Aug 03 '23 at 16:00
  • @TobySpeight definitely :) thanks for your feedback – Caparso Aug 03 '23 at 16:01
  • 1
    You can use `std::map` to map string labels to groups. – tadman Aug 03 '23 at 16:01

1 Answers1

1

There is cool library which address this issue Magic Enum.

It can make code work without extensive coding:

#include <iostream>
#include <memory>
#include <magic_enum.hpp>
#include <magic_enum_iostream.hpp>

using namespace magic_enum::ostream_operators; 
using namespace magic_enum::istream_operators; 

class Animal {
public:
    enum class Group {
        mammal,
        bird,
        reptile,
    };

    explicit Animal(Group g) : group { g } { 
        std::cout << "making: " << group << '\n';
    }

    ~Animal()
    {
        std::cout << "removing: " << group << '\n';
    }

private:
    Group group;
};

int main()
{
    Animal::Group g;
    while (std::cin >> g) {
        auto dog = std::make_unique<Animal>(g);
    }
    return 0;
}

https://godbolt.org/z/ae7nbvbEq

Disclaimer: Note that this library leverages some compiler specific features, so there is no warranty that it will always work. See limitations.

Marek R
  • 32,568
  • 6
  • 55
  • 140