0

I am trying to write the contents of a class object into a file. The object has an enum class member and I am unable to write it into a file using ofstream.

I get the following error.

error: no match for ‘operator<<’ (operand types are ‘std::basic_ostream<char>’ and ‘EnumClass_scope::EnumCass_name’)

Any leads would be helpful.

Abhishek V
  • 21
  • 1
  • 6
    Please provide a [mcve]. – Thomas Sablik Jun 12 '18 at 07:05
  • 5
    Did you overload ostream (<<) operator for the enum class? – nishantsingh Jun 12 '18 at 07:05
  • Welcome to stackoverflow.com. Please take some time to read [the help pages](http://stackoverflow.com/help), especially the sections named ["What topics can I ask about here?"](http://stackoverflow.com/help/on-topic) and ["What types of questions should I avoid asking?"](http://stackoverflow.com/help/dont-ask). Also please [take the tour](http://stackoverflow.com/tour) and [read about how to ask good questions](http://stackoverflow.com/help/how-to-ask). Lastly please learn how to create a [Minimal, Complete, and Verifiable Example](http://stackoverflow.com/help/mcve). – Some programmer dude Jun 12 '18 at 07:15
  • The compiler is telling you that it doesn't know how to output the enum. You have to provide an `operator <<` for it. – Goswin von Brederlow Jun 12 '18 at 07:53

3 Answers3

2

One way is to cast the enum type to the underlaying type. This can be done with already defined std::underlying_type_tto get the internal representation of the enum.

    template < typename T>
auto toUnderlayingType( T t )
{
    return static_cast<std::underlying_type_t< T >>( t );
}

    template < typename T, typename U = std::underlying_type_t< T > >
void readToEnum( U u , T& t )
{
    t = static_cast< T >( u );
}

class Y
{
    public:

        enum class X
        {
            ONE,
            TWO
        } x;

        Y(): x{X::ONE} { }

        void Print()
        {
            std::cout << toUnderlayingType(x) << std::endl;
        }

        void Read()
        {
            std::underlying_type_t< X > tmp;
            std::cin >> tmp;
            readToEnum( x, tmp );
        }
};



int main()
{
    Y y;
    y.Print();
}

But in the case of serialization it is even better to use a better representation of content and data. As reflection is still not part of c++ you have to convert the enum value to any useful output and back. Maybe you will write text like "ONE" instead of 0 to the file. But all this is to broad for this answer. There are a long list of serializer libraries like boost and cerial

And you have to check if the incoming value is a valid one. Having the example above and assign a numerical 3 to it, the enum value is invalid. That topic is already discussed here: What happens if you static_cast invalid value to enum class?

Klaus
  • 24,205
  • 7
  • 58
  • 113
2

Another option would be to manually overload the << operator for your enum:

#include <iostream>

enum class ESomething
{
    Nothing,
    Something,
    Everything,
};

std::ostream& operator<<(std::ostream& os, const ESomething& other)
{
    switch (other)
    {
    case ESomething::Nothing:
        os << "Nothing";
        break;
    case ESomething::Something:
        os << "Something";
        break;
    case ESomething::Everything:
        os << "Everything";
        break;
    default:
        break;        
    }
    return os;
    // Alternatively: std::cout << std::underlying_type(other); return os;
}

int main()
{
    ESomething hello = ESomething::Something;
    std::cout << hello << '\n';

    return 0;
}

Where you could decide exactly what to output on each separate case, or simply cast it to the underlying type as other answers have mentioned and output that. The choice is yours.

Carl
  • 2,057
  • 1
  • 15
  • 20
1

Convert variable to integer before writing. Use integer temporary variable when reading.

std::fstream stream;
enum class Enum { ... };

Enum variable;
stream << static_cast<int>(variable);

int temporary;
stream >> temporary;
variable = static_cast<Enum>(temporary);

If you defined enum with other type than int, use that type. For example, with enum class Enum : unsigned long long, use static_cast<unsigned long long>.

VLL
  • 9,634
  • 1
  • 29
  • 54
  • @andreee - An `enum` not convertible to an `int`, even with a cast? Than this is not C++. – StoryTeller - Unslander Monica Jun 12 '18 at 07:14
  • 2
    Personally, unless I was interested in a particularly terse serialisation (e.g. something on the lines of the XDR standard), I'd use a character string to serialise an `enum`. That way, any existing serialised data is less likely to be broken if the enum values change. – Bathsheba Jun 12 '18 at 07:14
  • @andreee - Neither are regular unscoped enumerations. Specifying the underlying type is not connected to scoping. Only implicit convertibility to the underlying type is. And either way, a cast to the underlying type will always work. Assuming `int` (which is the default for C++ enumerations) is also not unfounded. – StoryTeller - Unslander Monica Jun 12 '18 at 07:17
  • @andreee `enum class` is restricted to integral types, which are always castable to `int`. If you have used a type that is larger than `int`, you can use that type when writing the cast. – VLL Jun 12 '18 at 07:19
  • @Bathsheba - An obfuscated character string? Feels like leaking too much information for reverse engineering purposes, otherwise. – StoryTeller - Unslander Monica Jun 12 '18 at 07:22
  • Casting to int might loose precision. std::underlying_type_t seems to be the better answer here. – Goswin von Brederlow Jun 12 '18 at 07:52