-1

When using a scoped enum in a varargs context, it is defined to be passed as its underlying type, as answered in "Can I use enum class values as arguments to varargs functions?" As I understand it, this is the only circumstance in which a scoped enum will be converted implicitly, like an unscoped enum is.

Consider this program:

enum Foo : char { F };
enum class Bar : char { B };

#include <cstdio>
int main()
{
    return !std::printf("%c\n", Foo::F)
        +  !std::printf("%c\n", Bar::B);
}

The compiler (g++ version 6.3.0) is happy with the first print, of a Foo, but complains when I pass a Bar:

0.cpp: In function ‘int main()’:
0.cpp:10:34: warning: format ‘%c’ expects argument of type ‘int’, but argument 2 has type ‘Bar’ [-Wformat=]
         +  !printf("%c\n", Bar::B);
                                  ^

g++ version 4.8.2 didn't complain about this, but g++ 6.3.0 does (and that's why it now concerns me). Both versions complain about the first print when there is a substantive mismatch, such as using %f or %s, or if I change Foo to use a long underlying type; that's why I enable -Wformat.

I understand that warnings are not a standards-conformance issue, and I know how to change my code to address these (e.g. using the functions in answers to How can I output the value of an enum class in C++11?), but I also believe that warnings are unhelpful if they produce false positives. Is there any potential for actual harm in passing a scoped enum to a formatted I/O function when the underlying type of the enum matches the corresponding conversion specification in the format string?

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
  • 1
    GCC version 4.8 probably didn't complain because it didn't have a full C++11 implementation, and scoped enumerations was introduced in C++11. – Some programmer dude Feb 08 '17 at 09:14
  • 4
    See the accepted answer from the question you linked: Unscoped enum values are integer promoted, but scoped enums (the `enum class` ones) are not. – cpplearner Feb 08 '17 at 09:14
  • 1
    @cpplearner Even if I change `Bar` to be `enum class : int`, it complains of mismatch, so that's only part of the answer. – Toby Speight Feb 08 '17 at 09:33
  • @Toby no it's not: `enum class` signifies a new type without implicit conversions to `int` or the underlying type or whatever, these conversions still apply to plain `enum`. – rubenvb Feb 08 '17 at 10:06
  • @rubenvb, If there are no conversions, then that means that a scoped int passed through varargs can only be used if the `va_arg()` call uses exactly the same type? I think I understand now. Thanks to all who commented and answered! – Toby Speight Feb 08 '17 at 10:10

1 Answers1

5

From this scoped enumeration reference:

There are no implicit conversions from the values of a scoped enumerator to integral types, ...

[Emphasis mine]

That means no matter the base type, a scoped enumeration will not be implicitly converted to an int (or any other integer type). You must explicitly do the conversion, with e.g. static_cast (continued from previous quote):

... although static_cast may be used to obtain the numeric value of the enumerator.


Also, from this variadic argument reference:

bool, char, short, and unscoped enumerations are converted to int or wider integer types as in integer promotion

[Again emphasis mine]


And to answer your question if GCC is right in warning you: Yes it is right. What you're doing is not correct.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621