Объявлять типы без неявного преобразования в С++

Я хочу объявить свои собственные числовые типы, точно так же, как unsigned int, но я не хочу, чтобы типы были неявно преобразованы. Я попробовал это первым:   typedef unsigned int firstID;   typedef unsigned int secondID;

но это нехорошо, поскольку два типа являются просто синонимами для unsigned int, поэтому они свободно взаимозаменяемы.

Мне бы хотелось, чтобы это вызвало ошибку:

firstID fid = 0;
secondID sid = fid; // no implicit conversion error

но это будет хорошо:

firstID fid = 0;
secondID sid = static_cast<secondID>(fid); // no error

Моя причина в том, что аргументы функции строго типизированы, например:

void f( firstID, secondID ); // instead of void f(unsigned int, unsigned int)

Каков механизм, который я ищу?

Спасибо

Si

Ответы

Ответ 2

Как вы отметили: typedef плохо назван (он должен быть typealias (D имеет явно добавленные типы (последний раз, когда я смотрел))

Таким образом, единственный способ сделать это - создать два уникальных класса.
Я не собираюсь говорить, что вы не можете написать специализацию static_cast < > , чтобы делать то, что вы хотите, но я думаю (и я еще не так много думал об этом), так что было бы плохой идеей (даже если это юридический), я думаю, что лучший подход заключается в том, чтобы каждый конструктор классов использовал unsigned int, которые явны (поэтому нет автоматического преобразования).

 struct FID
 {
     explicit FID(unsigned int v): value(v) {}
     operator unsigned int() {return value;}
     unsigned int value;
 };

 class SID {/* Stuff */};

 FID   fid(1U);
 SID   sid(2U);

 doSomthingWithTwoSID(sid,SID(static_cast<unsigned int>(fid));

Создание явного конструктора означает отсутствие автоматического преобразования между типами.
Добавив встроенный оператор литья в unsigned int, вы можете использовать его везде, где ожидается int.

Ответ 3

Вам нужно написать свои собственные классы для них, переопределяя все необходимые вам операторы.

Ответ 4

Ахх, путешественник из Ады, которого я вижу.

Единственный реальный способ сделать это в С++ - объявлять классы. Что-то вроде:

class first_100 {
public:
    explicit first_100(int source) {
        if (source < 1 || source > 100) {
           throw range_error;
        }
        value = source;
    };
    // (redefine *all* the int operators here)
private:
    int value;
};

Вы захотите определить свой конструктор int explicit, чтобы С++ не использовал его для неявного преобразования между вашими типами. Таким образом это не сработает:

first_100 centum = first_100(55);
int i = centum;

но что-то вроде этого (если вы его определяете):

int i = centum.to_int();

Ответ 5

struct FirstID { int id; };