I've dealt with this situation before, for error codes.
I have seen people using enums for error codes, and this pose some issues:
- you can assign an int to the enum that doesn't not correspond to any value (too bad)
- the value itself is declared in a header, meaning that error code reassignment (this happens...) breaks code compatibility, you also have to take care when adding elements...
- you have to define all codes in the same header, even if often times some code are naturally restricted to a small portion of the application, because enums cannot be "extended"
- there is no check that a same code is not assigned twice
- you cannot iterate over the various fields of an enum
When designing my error codes solution, I thus chose another road: constants in a namespace, defined in source files, which address points 2 and 3. To gain in type safety though, the constants are not int, but a specific Code class:
namespace error { class Code; }
Then I can define several error files:
// error/common.hpp
namespace error
{
  extern Code const Unknown;
  extern Code const LostDatabaseConnection;
  extern Code const LostNASConnection;
}
// error/service1.hpp
// error/service2.hpp
I didn't solved the arbitrary cast issue though (constructor is explicit, but public), because in my case I was required to forward error codes returned by other servers, and I certainly didn't want to have to know them all (that would have been too brittle)
However I did thought about it, by making the required constructor private and enforcing the use of a builder, we're even going to get 4. and 5. in a swoop:
// error/code.hpp
namespace error
{
  class Code;
  template <size_t constant> Code const& Make(); // not defined here
  class Code: boost::totally_ordered<Code>
  {
  public:
    Code(): m(0) {} // Default Construction is useful, 0 is therefore invalid
    bool operator<(Code const& rhs) const { return m < rhs.m; }
    bool operator==(Code const& rhs) const { return m == rhs.m; }
  private:
    template <size_t> friend Code const& Make();
    explicit Code(size_t c): m(c) { assert(c && "Code - 0 means invalid"); }
    size_t m;
  };
  std::set<Code> const& Codes();
}
// error/privateheader.hpp (inaccessible to clients)
namespace error
{
  std::set<Code>& PrivateCodes() { static std::set<Code> Set; return Set; }
  std::set<Code> const& Codes() { return PrivateCodes(); }
  template <size_t constant>
  Code const& Make()
  {
    static std::pair< std::set<Code>::iterator, bool > r
      = PrivateCodes().insert(Code(constant));
    assert(r.second && "Make - same code redeclared");
    return *(r.first);
  }
}
//
// We use a macro trick to create a function whose name depends
// on the code therefore, if the same value is assigned twice, the
// linker should complain about two functions having the same name
// at the condition that both are located into the same namespace
//
#define MAKE_NEW_ERROR_CODE(name, value)         \
  Make<value>(); void _make_new_code_##value ();
// error/common.cpp
#include "error/common.hpp"
#include "privateheader.hpp"
namespace error
{
  Code const Unkown = MAKE_NEW_ERROR_CODE(1)
  /// ....
}
A tad more work (for the framework), and only link-time/run-time check of the same assignment check. Though it's easy to diagnose duplicates simply by scanning for the pattern MAKE_NEW_ERROR_CODE
Have fun!