Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ implicit conversion to bool

In an effort to make my enums more typesafe, I've been using macro-generated overloaded operators to disallow comparing enums against anything but an identically typed enum:

#include <boost/static_assert.hpp>

#define MAKE_ENUM_OPERATOR_TYPESAFE(enumtype, op) \
  template<typename T> \
  inline bool operator op(enumtype lhs, T rhs) \
  { \
    BOOST_STATIC_ASSERT(sizeof(T) == 0); \
    return false; \
  } \
  \
  template<> \
  inline bool operator op(enumtype lhs, enumtype rhs) \
  { \
    return static_cast<int>(lhs) op static_cast<int>(rhs); \
  }

#define MAKE_ENUM_TYPESAFE(enumtype) \
  MAKE_ENUM_OPERATOR_TYPESAFE(enumtype, ==) \
  MAKE_ENUM_OPERATOR_TYPESAFE(enumtype, !=) \
  MAKE_ENUM_OPERATOR_TYPESAFE(enumtype, >) \
  MAKE_ENUM_OPERATOR_TYPESAFE(enumtype, <) \
  MAKE_ENUM_OPERATOR_TYPESAFE(enumtype, >=) \
  MAKE_ENUM_OPERATOR_TYPESAFE(enumtype, <=)

// Sample usage:
enum ColorType { NO_COLOR, RED, BLUE, GREEN };
MAKE_ENUM_TYPESAFE(ColorType)

This generally has the desired effect; comparisons of the form color_variable == RED work, while comparisons of the form color_variable == 1 generate compile-time errors thanks to Boost.StaticAssert. (Is this a decent approach?)

However, my compiler (CodeGear C++Builder) is also trying to use these overloaded operators to implement implicit bool conversions. For example, if (color_variable) { ... } is being translated to if (operator!=(color_variable, 0)) { ... } and is triggering the BOOST_STATIC_ASSERT and failing to compile.

I'm fairly certain that this is incorrect behavior on the part of my compiler (Comeau and GCC don't do it, for example) but was wondering if there are any language lawyers present who could confirm. I tried looking up in the C++0x draft standard myself, but all I could find was the following statement under section 4.12:

A zero value, null pointer value, or null member pointer value is converted to false; any other value is converted to true.

without details as to how "a zero value" is checked for.

like image 642
Josh Kelley Avatar asked Nov 03 '09 14:11

Josh Kelley


1 Answers

Why don't you use a class like following?

template<class Enum>
class ClassEnum
{
public:
  explicit ClassEnum(Enum value) : value(value) {}
  inline bool operator ==(ClassEnum rhs) { return value == rhs.value; }
  inline bool operator !=(ClassEnum rhs) { return value != rhs.value; }
  inline bool operator <=(ClassEnum rhs) { return value <= rhs.value; }
  inline bool operator >=(ClassEnum rhs) { return value >= rhs.value; }
  inline bool operator  <(ClassEnum rhs) { return value < rhs.value; }
  inline bool operator  >(ClassEnum rhs) { return value > rhs.value; }

  // Other  operators...
private:
  Enum value;
}

enum ColorTypeEnum { NO_COLOR, RED, BLUE, GREEN };
typedef ClassEnum<ColorTypeEnum> ColorType;

There is no implicit conversion to bool for ClassEnum<ColorTypeEnum>.

like image 113
Alexey Malistov Avatar answered Oct 23 '22 23:10

Alexey Malistov