Как вы, наверное, знаете, typedef больше похож на псевдоним в C ++, а не на новый тип, подробности можно посмотреть здесь:
http://dlang.org/cpptod.html#typedefs
Мне действительно не нравится решение, предложенное в ссылке, поэтому мне интересно, есть ли лучший способ?
Существует только один способ ввести новый тип в C ++ — с помощью ключевого слова class (union
/struct
/class
/enum
…). Есть способы скрыть эти вещи за макросами и сделать эти новые типы такими же интуитивно понятными, как и старые (см. BOOST_STRONG_TYPEDEF
), но факт остается фактом, что это единственный способ ввести этот новый тип.
Представь, что у тебя был newtype
ключевое слово, которое делает сильный typedef:
newtype foo = int; // with 'using' alias syntax
Как будут работать преобразования в этот тип и из него? Без преобразований вы никогда не сможете присвоить какое-либо значение объекту вашего нового типа. Только явные преобразования могут показаться интуитивно понятными, но что если вы действительно хотите неявные преобразования, и все же сможете перегружать? Ну, удачи. Возможно, вы сможете добавить все виды синтаксиса, чтобы оставить решение за пользователем, но я уверен, что вы всегда можете придумать угловые случаи, которые требуют нового синтаксиса. Просто сделай это struct
, скройте это за макросом и покончите с этим.
Универсальный макрос «нет времени создавать правильный интерфейс»:
#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;} \
};
Если ваш компилятор не поддерживает шаблоны с переменным числом аргументов, вам нужно будет вручную вставить любые необходимые вам конструкторы. В основном это наследующий конструктор build-your-own.
К сожалению, я не думаю, что можно ограничить неявное приведение нового типа к базе, но раскрыть все его открытые поля. Есть несколько обходных путей:
Вы можете просто 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
Честное предупреждение, я не испытал ничего, кроме базовой механики. Это может добавить (очень) небольшое количество накладных расходов. Но фактически пустой класс наверное оптимизирован прочь
использование BOOST_STRONG_TYPEDEF
создать «strongdefs» в C ++. Для этого нет встроенной функции языка.
Тем не менее, было бы интересно узнать реальную проблему, которую вы пытаетесь решить, потому что я нашел необходимость в не псевдонимах. typedef
быть очень минимальным в коде, над которым я работал.
Новые типы в C ++ могут быть получены только путем объединения подтипов. Но поскольку перегрузка функции основана на статическом типе, все операции и функции должны быть объявлены повторно.
C ++ typedef
s как D alias
эс.
В случае, если начальный тип является классом или структурой, наследование может как-то помочь (по крайней мере, операции могут работать как со старыми параметрами), но все относится к типу возвращаемого значения и преобразование должно быть переопределено правильно, в противном случае все преобразовывается безразлично вверх и вниз, таким образом исчезая Преимущество нового типа.
В C ++ есть много способов выполнить проверку типов.
Рассмотрим следующий код, основная идея такая же, как в примере, приведенном в ссылке, но я думаю, что это более просто:
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);
}