Why We Couldn't Use Two Different enum Interchangeable?, e.g. As Function Parameter?

Viewed 107

With this code:

enum A { _1 };
enum B { _2 };

void f(A) {}

int main()
{
        f(_2);
}

A C++ compiler complains that couldn't convert B to A (try it on Wandbox), But with a C compiler we just get a warning (I know C++ is not C):

main.c: In function ‘f’:
main.c:11:6: warning: type of ‘A’ defaults to ‘int’ [-Wimplicit-int]
   11 | void f(A)
      |      ^
main.c:11:6: warning: unused parameter ‘A’ [-Wunused-parameter]

Which it's make sense (for me) because as far as I know: An enum is just an int (whatever short int, int, ... depending on the value of the enumerations). So:

  1. Why the C++ compiler doesn't let me use B as A?
  2. And it's fine to use f(static_cast<A>(_2));?

My environment:

  • Compiler: GCC 11.1.0
  • Compiler Flags: -Wall -Wextra -Wpedantic
  • OS: ArchLinux 5.13.13-arch1-1
1 Answers

In C++, the function

void f(A) {}

is interpreted to mean “a function named f that takes an argument of type A, and its parameter has no name.” However, the C language requires that all function parameters have names (this is different than C++), so C interprets this as “a function f that takes a parameter named A, and since A has no associated type the compiler thinks it’s looking at older C code in which parameters with no names have type int, so that’s a function named f taking an int named A.” The warning you get from gcc is trying to tell you that, but it’s hard to know what it means without that backstory. (The use of function parameters without types as implicitly being integers is something that hasn’t been legal C for decades, but for backwards compatibility some C compilers accept it anyway.)

Independently - enumerated types have integral values but are not themselves integers. In both C and C++ you can implicitly convert an integer to an enumerated type. However, in C++ (and I believe C as well, but I’m not sure) enumerated values aren’t integers and can’t be treated as enumerated values of another type without a cast. So yes, you could call the function by explicitly casting one enumerated type to another, but you can’t call the function by passing an enumerated constant of the wrong type.

Related