Enum.cpp
// Enum.cpp
//
// Author David Barrett-Lennard
// (C)opyright Cedanet Pty Ltd 2009
#include "Ceda/cxUtils/Tracer.h"
#include "Ceda/cxUtils/Archive.h"
@import "ExampleUtils.h"
void TraceInfoAboutEnum(const ceda::ReflectedEnum& re)
{
Tracer() << "GetName() = " << re.GetName() << '\n'
<< "ValuesRedefined() = " << re.ValuesRedefined() << '\n'
<< "GetCount() = " << re.GetCount() << '\n';
for (int i=0 ; i < re.GetCount() ; ++i)
{
Tracer() << "GetValue(" << i << ") = " << re.GetValue(i) << ' '
<< "GetEnable(" << i << ") = " << re.GetEnable(i) << ' '
<< "GetString(" << i << ") = " << re.GetString(i) << '\n';
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
/*
A C++ enumerated type can be reflected using $enum
Labels can be marked as deprecated by preceding with '-'.
*/
namespace Enum1
{
// enums can be forward declared.
// The forward declaration must not use '+'
// The declaration must use 'class' if and only if the definition uses 'class'
$enum Colour;
$enum+ Colour
{
COL_R,
COL_G,
COL_B,
};
$enum+ Status
{
warn,
-failed, // '-' means deprecated
error,
success,
};
$enum+ Chip
{
red,
green,
blue,
black = 10,
white
};
void Run()
{
ceda::TraceGroup g("Enum example 1");
int x = COL_R;
int y = COL_R + 10;
Colour c = COL_G;
// Note that deprecated labels are still available!
Status s = failed;
const ceda::ReflectedEnum& reColour = ceda::FindReflectedEnum("Enum1::Colour");
TraceInfoAboutEnum(reColour);
Tracer() << '\n';
const ceda::ReflectedEnum& reStatus = ceda::FindReflectedEnum("Enum1::Status");
TraceInfoAboutEnum(reStatus);
Tracer() << '\n';
const ceda::ReflectedEnum& reChip = ceda::FindReflectedEnum("Enum1::Chip");
TraceInfoAboutEnum(reChip);
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
/*
A $enum class definition causes xcpp to generate a class that represents the enum.
*/
namespace Enum2
{
// Forward declaration. Note that it uses 'class' consistently with the definition
$enum class Bool;
$enum+ class Bool
{
False,
True
};
$enum+ class Colour // 'class' causes a class for the enum to be generated by xcpp
{
R,
default G, // Default used for the default constructor
B,
-M, // '-' indicates that this label is flagged as deprecated
C,
Y,
};
$enum+ class Strange
{
x,
default -y // Making a deprecated label the default is supported!
};
void f1(int) {}
void f2(bool) {}
void f3(Colour c = Colour::G) {}
void f4(Colour) {}
void Run()
{
ceda::TraceGroup g("Enum example 2");
// FindReflectedEnum() looks for the reflected enum in a global registry
TraceInfoAboutEnum(ceda::FindReflectedEnum("Enum2::Bool"));
Tracer() << '\n';
// GetReflectedEnum<T>() gets the ReflectedEnum of type T.
TraceInfoAboutEnum(ceda::GetReflectedEnum<Colour>());
Tracer() << '\n';
TraceInfoAboutEnum(ceda::GetReflectedEnum<Strange>());
Tracer() << '\n';
/*
The default value is normally the first value that appears in the enum.
*/
Bool b;
cxAssert(b == Bool::False);
// Colour::LEN is a compile time const that for example can be used to declare the size of
// an array
int A[Colour::LEN]; A[0] = 10;
Colour c(Colour::G); // construction from enum value
c = Colour::B; // assignment from enum value
f4(Colour::R);
// error C2679: binary '=' : no operator found which takes a right-hand operand of type 'int'
// (or there is no acceptable conversion)
// c = 1;
// error C2676: binary '++' : 'Colour' does not define this operator or a conversion to a type
// acceptable to the predefined operator
// c++;
// warning C4800: 'Colour::Enum' : forcing value to bool 'true' or 'false' (performance warning)
// bool b = c;
// error C2440: 'initializing' : cannot convert from 'Colour' to 'const char *'
// const char* str = c;
/*
We follow the normal convention of allowing implicit conversion to int. This could be regarded
as risky, but would set too big a precedent to disallow it.
*/
int x = c; // Implicit conversion to int
int y = c+1;
int z = c * 10;
f1(c);
// All possible comparisons between colours and ints
f2(10 == c); f2(10 != c);
f2(10 < c); f2(10 <= c);
f2(10 > c); f2(10 >= c);
f2(c == 10); f2(c != 10);
f2(c < 10); f2(c <= 10);
f2(c > 10); f2(c >= 10);
// All possible comparisons between colours and enum values
f2(Colour::R == c); f2(Colour::R != c);
f2(Colour::R < c); f2(Colour::R <= c);
f2(Colour::R > c); f2(Colour::R >= c);
f2(c == Colour::R); f2(c != Colour::R);
f2(c < Colour::R); f2(c <= Colour::R);
f2(c > Colour::R); f2(c >= Colour::R);
Colour c1; // Default ctor
cxAssert(c1 == Colour::G);
Colour c2(c1); // Copy ctor
c2 = c1; // Assignment
// All possible comparisons between colours
f2(c1 == c2); f2(c1 != c2);
f2(c1 < c2); f2(c1 <= c2);
f2(c1 > c2); f2(c1 >= c2);
// error C2440: 'initializing' : cannot convert from 'int' to 'Colour'
// Colour c3 = 1;
Colour::Enum e1; // Cannot predict value of e1!
e1 = Colour::R;
// error C2440: 'initializing' : cannot convert from 'int' to 'Colour::Enum'
// Colour::Enum e2 = 1;
ceda::TracerX os;
// Forwards iteration
for (Colour::iterator i = Colour::begin() ; i != Colour::end() ; ++i)
{
os << *i << ' ';
}
os << '\n';
for (Colour::iterator i = Colour::G ; i != Colour::end() ; ++i)
{
os << *i << ' ';
}
os << '\n';
// Reverse iteration
for (Colour::reverse_iterator i = Colour::rbegin() ; i != Colour::rend() ; ++i)
{
os << *i << ' ';
}
os << '\n';
/*
if (false)
{
ceda::Archive ar;
ar << c;
}
*/
if (false)
{
ceda::InputArchive ar(0);
ar >> c;
}
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
/*
A $enum class definition causes xcpp to generate a class that represents the enum.
*/
namespace Enum3
{
$enum+ class Colour // 'class' causes a class for the enum to be generated by xcpp
{
R,
default G, // Default used for the default constructor
B,
-M, // '-' indicates that this label is flagged as deprecated
C = 10, // Causes a mismatch between 'index' and 'value'
Y,
};
void f1(int x) {}
void f2(bool x) {}
void Run()
{
ceda::TraceGroup g("Enum example 3");
TraceInfoAboutEnum(ceda::FindReflectedEnum("Enum2::Colour"));
Tracer() << '\n';
ceda::TracerX os;
// Prints 'C = 10'
// Note that Colour(Colour::C).c_str() involves a scan for the index that maps to value Colour::C = 10
Tracer() << Colour(Colour::C) << " = " << Colour::C << '\n';
// This initialisation actually involves a scan for the index that maps to value Colour::C = 10
Colour::iterator j = Colour::C;
os << "j = " << *j << '\n';
// This initialisation actually involves a scan for the index that maps to value Colour::C = 10
Colour::iterator k = Colour(Colour::C);
os << "k = " << *k << '\n';
// Forwards iteration
os << '\n';
for (Colour::iterator i = Colour::begin() ; i != Colour::end() ; ++i)
{
os << i.c_str() << ' '; // Fast - iterator directly indexes into array of strings
os << *i << ' '; // Slow - to display string the index is mapped to a value by linear search!
os << (int)(*i) << '\n'; // Provides access to the value as an int
}
os << '\n';
// Reverse iteration
for (Colour::reverse_iterator i = Colour::rbegin() ; i != Colour::rend() ; ++i)
{
os << i.c_str() << ' ';
os << *i << ' ';
os << (int) (*i) << '\n';
}
os << '\n';
}
}
///////////////////////////////////////////////////////////////////////////////////////////////////
namespace Enum
{
void Run()
{
Enum1::Run();
Enum2::Run();
Enum3::Run();
}
}