#include <iostream>
#include <string>
#include <map>
// define some tags to create uniqueness
struct portal_tag {};
struct cake_tag {};
// a string-like identifier that is typed on a tag type
template<class Tag, class Base>
struct strong_type
{
// needs to be default-constuctable because of use in map[] below
strong_type(Base s) : _value(std::move(s)) {}
strong_type() : _value() {}
// provide access to the underlying string value
const Base& value() const { return _value; }
private:
Base _value;
// will only compare against same type of id.
friend bool operator < (const strong_type& l, const strong_type& r) {
return l._value < r._value;
}
};
// create some type aliases for ease of use
using PortalId = strong_type<portal_tag, std::string>;
using CakeId = strong_type<cake_tag, std::string>;
using namespace std;
// confirm that requirements are met
auto main() -> int
{
PortalId portal_id("2");
CakeId cake_id("is a lie");
std::map<CakeId, PortalId> p_to_cake; // OK
p_to_cake[cake_id] = portal_id; // OK
//p_to_cake[portal_id] = cake_id; // COMPILER ERROR
//portal_id = cake_id; // COMPILER ERROR
//portal_id = "1.0"; // COMPILER ERROR
portal_id = PortalId("42"); // OK
return 0;
}