Подтвердить что ты не робот

Есть ли способ имитации "strongdef"?

Как вы, наверное, знаете, что typedef больше похож на псевдоним в С++, а не на новый тип, подробности можно увидеть здесь: http://dlang.org/cpptod.html#typedefs
Мне действительно не нравится решение, предложенное в ссылке, поэтому мне интересно, есть ли лучший способ?

4b9b3361

Ответ 1

Существует только один способ ввести новый тип в С++ - с ключевым словом класса (union/struct/class/enum...). Есть способы скрыть этот материал за макросами и сделать эти новые типы интуитивно понятными, как старые (см. BOOST_STRONG_TYPEDEF), но факт остается, что это единственный способ ввести этот новый тип.

Представьте, что у вас есть ключевое слово newtype, которое делает сильный typedef:

newtype foo = int; // with 'using' alias syntax

Как будут выполняться преобразования и из этого типа? Без конверсий вы никогда не сможете присвоить какое-либо значение объекту вашего нового типа. Только явные преобразования могут показаться интуитивными, но что делать, если вы действительно хотите неявных преобразований и все еще можете перегружать? Ну, тяжелая удача. Вы могли бы добавить все виды синтаксиса, чтобы оставить решение для пользователя, но я уверен, что вы всегда можете придумать угловые случаи, которые потребуют нового синтаксиса. Просто сделайте это struct, спрячьте его за макросом и сделайте с ним.

Ответ 2

Общий "время для создания правильного интерфейса":

#define STRONG_CLASS_TYPEDEF(oldType, newType) \
struct newType : private oldType {             \
    template<typename... T>                    \
    newType(T... foo) : oldType(foo...) {}     \
    oldType* operator->() { return this; }     \
    oldType& operator*() {return *this;}       \
};

Если ваш компилятор не поддерживает вариативные шаблоны, вам нужно вручную вставить любые необходимые вам конструкторы. Это в основном собственный конструктор наследования, построенный на свой собственный.

К сожалению, я не думаю, что можно ограничить новый тип неявным кастингом на базу, но выставить все его публичные поля. Существует несколько способов:

Вы можете просто using oldType::X; использовать все методы и переменные, которые вам нужны. Это, безусловно, лучшее решение, но требуется некоторое время.

Или используйте перегрузку оператора скрытой стрелки и вызовите foo->method();. Или "разыгрывать" новый сильный тип в базовый тип. Это в основном просто причудливый явный актерский состав. Но, учитывая operator oldType() (явный или нет), даже не работает с частным наследованием...

В любом случае, здесь сильный тип для примера std::string и Name.

struct Name : private std::string {
    template<typename... T>
    Name(T... foo) : std::string(foo...) {}

    std::string* operator->() { return this; }
    const std::string& operator*() {return *this;}
    //The above is obviously a bad idea if you want to use this alongside pointers

    using std::string::resize;
    using std::string::size;
    using std::string::insert;
    using std::string::operator[];
    // etc.
    //Simplest to use, but a bit more to set up
};

Кроме того, вам придется обернуть перегрузку операторов, отличных от членов (std::string == в этом примере).

bool operator==(Name& lhs, Name& rhs) { return *lhs == *rhs; }
//Note: "Dereference" turns it into a std::string, as above

Справедливое предупреждение, я не испытал многого за пределами основной механики. Это может добавить (очень) небольшое количество накладных расходов. Но фактически пустой класс, вероятно, оптимизирован.

Ответ 3

Используйте BOOST_STRONG_TYPEDEF для создания "strongdefs" на С++. Для этого нет встроенной языковой функции.

Было бы интересно узнать реальную проблему, которую вы пытаетесь решить, потому что я нашел необходимость в том, чтобы не-псевдоним typedef был очень минимальным для кода, над которым я работал.

Ответ 4

Новые типы на С++ могут приводить только к каким-то агрегатным подтипам. Но поскольку перегрузка функций основана на статическом типе, все операции и функции должны быть обновлены.

С++ typedef похожи на D alias es.

В случае, если начальный тип является классом или структурой, наследование может каким-то образом помочь (по крайней мере, операции могут работать как со старыми параметрами), но все идет о типе возврата, и преобразование должно быть переопределено должным образом, в противном случае все преобразуется равномерно вверх и вниз, тем самым исчезая преимущество нового типа.

Ответ 5

В С++ существует множество способов выполнения проверки типов. Рассмотрим следующий код: основная идея такая же, как в примере, приведенном в ссылке, но я думаю, что это более просто:

struct Handle2 {void * ptr;} ;
void bar(Handle2) {}
void foo(void *) {}

int main() {
    Handle2 h2 = {(void*)-1};
    foo(h2); //! won't pass through compiling
    bar(h2);
}